为什么 async 中的 catch 不等待代码触发?

Why doesn't the catch in async await code fire?

是否有任何 .catch() 方法,就像 async await 代码风格的 Promises 一样?

这是一个通过 Promise 编写的代码示例:

const apiURL = 'https://jsonplaceholder.typicode.com/todos/1';
const badURL = 'zhttps://wcaf.fajfkajf.gg'

function getData(url){
  fetch(url)
    .then(response => response.json())
    .then(json => console.log(json))
      .catch( err => console.log('cannot load api'))
}
  
getData(apiURL);
getData(badURL);

一个尝试加载数据的简单函数,如果没有,则显示基本错误消息。现在我想把它转录成 async/await 风格的代码,问题是,我真的想不出用 catch()

写这个的方法

我最好的猜测是尝试 try - catch 但 catch 部分不起作用:

const apiURL = 'https://jsonplaceholder.typicode.com/todos/1';
const badURL = 'zhttps://wcaf.fajfkajf.gg'

async function getData(url){
  const response = await fetch(url);
  try {
     const json = await response.json();
     console.log(json);
  } catch (e) {
     console.log('cannot load api');
  }
}
  
getData(apiURL);
getData(badURL);

这会很好地加载对象 API,但似乎永远不会进入 catch{} 块,尽管传递不正确 url.

知道我做错了什么吗?

As pointed out in the comments by @l-portet, this is because the code inside try { } block does not actually fail!

.json() 将 return 承诺,无论解析的正文文本 的内容如何,​​因此即使初始 fetch() 失败,您仍然可以对其调用 .json() - 尽管它是完全多余的,因为它 return 没有任何意义。

fetch() 请求放入 try { } 块中确实会产生预期的行为:

const apiURL = 'https://jsonplaceholder.typicode.com/todos/1';
const badURL = 'zhttps://wcaf.fajfkajf.gg'

async function getData(url){
  try {
     const response = await fetch(url);
     const json = await response.json();
     console.log(json);
  } catch (e) {
     console.log('cannot load api');
  }
}
  
getData(apiURL);
getData(badURL);

你应该知道的一件事是,当一个 async 函数被执行时,它 总是 return 一个承诺 ,不管函数的退出条件功能。

如果该函数具有明确的 return(或在不崩溃的情况下完成),promise 将 resolved 为它 returned 的值(或undefined 如果没有显式 return),如果函数抛出,promise 将被拒绝,传递抛出的错误对象。

知道你可以简单地处理你使用函数的错误,例如:

const apiURL = 'https://jsonplaceholder.typicode.com/todos/1';
const badURL = 'zhttps://wcaf.fajfkajf.gg'

async function getData(url){
  const response = await fetch(url);
  return await response.json();
}
  
getData(apiURL).then(data => console.log(data));
getData(badURL).catch(err => console.log('error:', err));

恕我直言,在函数 use-case 处密切处理错误更有意义,因为通常情况下,当您期望出现错误时,是因为我们有办法处理它(也许尝试另一个 API url 在这个例子中)。

我最近一直在使用的一种模式是按照 [error, value] 的约定(类似于 Go 编程语言的方式)以解析 return 元组的方式包装承诺handle async error),例如,您可以在特定的 getData 调用中处理错误,例如:

const apiURL = 'https://jsonplaceholder.typicode.com/todos/1';
const badURL = 'zhttps://wcaf.fajfkajf.gg'

async function getData(url){
  const response = await fetch(url);
  return await response.json();
}

// simple utility function
const safePromise = promise =>
  promise.then(data => [null, data]).catch(err => [err, undefined]);

(async () => {
  const [err, json] = await safePromise(getData(apiURL))
  if (err) {
    // handle the error
  }
  console.log(json)

  const [error, data] = await safePromise(getData(badURL))
  if (error) {
    console.log('Error:', error);
  }
})()

检查以下基本包含此模式的库: