分类
js

记一个 `try…catch` 异步函数的坑

前几天遇到一个问题:想捕获异步函数的错误,但是捕获不到。我的代码大概是这样:

try {
  (async () => {
    // 一大堆异步函数
  })();
} catch (e) {
  if (e.message.startsWith('my error:') {
    // 我的错误,提示一下即可
  } else {
    // 某种不知名错误,继续抛出
    throw new Error(e.message);
  }
}

不知道读者是否发现问题,我当时是左看右看没看出来。后来只好写最小用例缩小问题范围,终于找到问题所在:异步函数前面缺少 await。于是想通了,上面的代码其实被引擎解释成:

  1. try 一个函数
  2. 这个函数的返回值是一个 Promise
  3. Promise 是正常对象,所以 try 成功
  4. 至于 Promise 里的函数是否失败,不关 try 的事,所以自然捕获不到

所以正确的写法是:

// 外面先套一层,不然不能用 await
(async () => {
  try {
    // 再加上 `await`
    await (async () => {
      // 异步函数体
    })();
  } catch (e) {
    // ....
  }
})();

这个 await 至关重要。这是异步函数的一大特性,即 try...catch 可以捕获整个异步操作前后所有栈的异常,而不仅仅是当前函数的异常。同时我们也要注意,异步函数的调用可能并不在当前栈,也无法被 try...catch 在当前栈捕获到错误。

meathill

爱编程,爱旅游,爱吐槽。
今年的目标是完成并运营至少一个 Side Project。
《Electron + Vue 实战开发》龟速创作中……

“记一个 `try…catch` 异步函数的坑”上的2条回复

肉山哥你好,前面的都看明白了,最后一句“异步函数的调用可能并不在当前栈,也无法被 try…catch 在当前栈捕获到错误”没太看懂,可以展开说一下吗?

欢迎吐槽,共同进步

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据