混合使用 .catch() 和 async/await 处理错误是否可行?

5

通常在JavaScript中处理async/await的错误时,人们默认使用try/catch。但是我想知道是否可以改用.catch(),如下所示:


  const res = await fetch().catch((error) => (
    // error handling
  ));

  const json = await res.json();


我想知道这是否与try/catch块的工作方式相同。
  try {
    const res = await fetch()
    const json = await res.json();
  } catch(e) {
    // error handling
  }  

我知道从技术上讲,try/catch块也可以捕获由res.json();引发的错误,所以我猜还是优先使用.catch()的例子?


3
问题在于,如果您捕获了这样的错误,函数将继续执行并运行res.json()。它可能会抛出一个错误,或者什么也不返回,我不确定,但它会导致预期之外的行为。 - Konrad
你的第一个例子需要使用 then() 而不是 await,这样你就可以解析 JSON 并捕获任何错误:fetch(bla).then(res => res.json()).catch(err) - Kokodoko
1个回答

13
我想知道这是否与try/catch块相同。
不是,正如你自己已经回答的那样。特别地,包围res.json()的try块也会捕获从中抛出的错误,这可能是你想要的,也可能不是。
此外,如果您没有从.catch()回调中重新引发异常,则其返回值将成为res值,并且仍将在其上调用res.json(),因此最好返回有效的Response实例。
可以混合使用.catch()和async/await进行错误处理吗?

是的,绝对没问题!如果您想仅处理一个特定promise的错误,那么.catch()是一个更加灵活的工具。使用try/catch来做这件事情会更加丑陋, 因此我甚至建议在重新抛出错误时使用.catch()(当您需要更好的错误消息时):

const res = await fetch(…).catch(error => {
  throw new Error('Could not reach backend', {cause: error});
});
if (!res.ok) throw new Error(`Backend responded with ${res.status} error: ${await res.text()}`);
const data = await res.json();

如果您不想重新抛出,我建议使用 .then() 分别处理成功和失败路径
const data = await fetch(…).then(res => {
  if (!res.ok) {
    console.error(`Backend responded with ${res.status} error`);
    return null;
  }
  return res.json();
}, error => {
  console.error('Could not reach backend', error);
  return null;
});

谢谢你的回答!有两个快速问题:1. 在你写的第一个例子中,当你在await fetch(…).catch(error => { }中重新抛出错误时,我想知道这样做会如何改善?而且由于没有另一个catch来捕获错误,这样做不会导致崩溃吗?2. 如果将catchawait混合使用确实很好,那么是否有任何真实的代码库/库/开源项目使用这种模式而不是简单的then().catch()try catch?感谢您的回答!有两个问题要问:1. 在您提供的第一个示例中,您在await fetch(…).catch(error => { }中重新抛出错误,我想知道这样做会如何改进?并且由于没有其他catch来捕获该错误,这样做是否会导致崩溃?2. 如果将catchawait混合使用确实很好,那么是否有任何真实世界的代码库/库/开源项目使用这种模式而不是简单的then().catch()try catch - Joji
@Joji 它重新抛出了一个带有更好上下文信息的不同错误。但是是的,新错误仍然需要在某个地方进行处理(向用户显示?)。当然,如果您实际上可以在.catch()回调中处理错误(并使用适当的内容 - 来自缓存或其他东西 - 返回new Response),则可以这样做,我只是无法想出一个好的示例。 - Bergi
@Joji 关于使用这种模式的开源代码库,我不知道有哪些或者如何搜索它们,但我肯定在实际生产代码中使用了这种模式。 - Bergi
@Joji 这份文档 中写道:"当我们使用 async/await 时,可以使用常规的 try..catch 而不是 .catch。这通常(但并非总是)更方便。" 这篇博客文章 讨论了一些模式,如果不想包装整个代码,则不使用 try/catch - Bergi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接