async函数中的错误处理?

使用async/await编写异步代码时,错误处理的方式与同步代码高度一致,这大大提升了可读性。核心原则是:await表达式会“抛出”被拒绝的Promise,因此我们需要用try...catch块来捕获这些错误,这与处理同步throw语句完全一样。

使用try…catch进行局部捕获

最直接、最常用的方法是在async函数内部使用try...catch语句包裹await表达式。

async function fetchData(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('获取数据失败:', error.message);
    // 可以在这里进行错误恢复、上报或返回默认值
    return { default: 'value' };
  }
}

这种方式让你能在一个集中的位置处理特定操作链中可能发生的所有错误,无论是网络失败、JSON解析错误还是手动抛出的业务逻辑错误。

在调用处使用.catch捕获

由于async函数总是返回一个Promise,你也可以在调用这个函数时,使用.catch()方法来捕获从函数内部抛出的错误。

async function dangerousOperation() {
  const result = await someAsyncTask();
  if (!result.valid) {
    throw new Error('结果无效');
  }
  return result;
}

// 在调用处捕获
dangerousOperation()
  .then(data => console.log('成功:', data))
  .catch(error => console.error('外部捕获:', error));

这种方式将错误处理的责任交给了调用者,更符合函数式编程中让纯函数只关心成功路径、由外部处理异常的思想。它适合在多个地方调用同一个async函数,且错误处理逻辑可能不同的场景。

结合Promise.all等组合器的错误处理

当使用Promise.all()并发执行多个async函数时,Promise.all本身的快速失败特性会影响错误捕获。

async function fetchMultiple(urls) {
  try {
    // 如果任何一个请求失败,整个Promise.all会立即拒绝
    const results = await Promise.all(urls.map(url => fetch(url)));
    return results;
  } catch (error) {
    console.error('有一个请求失败了:', error);
    // 你可能希望知道其他成功请求的结果,这时可以使用 Promise.allSettled
  }
}

// 使用 Promise.allSettled 获取所有结果
async function fetchAllSettled(urls) {
  const results = await Promise.allSettled(urls.map(url => fetch(url)));
  const successful = results.filter(r => r.status === 'fulfilled');
  const errors = results.filter(r => r.status === 'rejected');
  return { successful, errors };
}

Promise.allSettled()会等待所有Promise落定,不会因为个别失败而提前退出,这让你能更精细地处理部分成功、部分失败的情况。

未捕获错误的全局处理

如果async函数中的错误既没有被内部的try...catch捕获,也没有被外部的.catch()处理,那么这个被拒绝的Promise将会导致一个“未处理的Promise拒绝”。在浏览器和Node.js中,可以监听相应事件来全局捕获。

// 浏览器
window.addEventListener('unhandledrejection', event => {
  console.error('全局捕获到未处理的Promise拒绝:', event.reason);
});

// Node.js
process.on('unhandledRejection', (reason, promise) => {
  console.error('未处理的拒绝:', reason);
});

良好的错误处理策略应该是分层的:在async函数内部处理可恢复的错误;在调用处处理业务逻辑错误;最后设置全局兜底以防遗漏。这使得应用既健壮又易于调试。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容