一聚教程网:一个值得你收藏的教程网站

热门教程

async await 怎么捕获异步回调函数中的异常

时间:2026-07-12 10:51:56 编辑:袖梨 来源:一聚教程网

async/await 通过 try/catch 捕获 await 的 Promise rejection,而非回调内 throw;需将回调(如 fs.readFile)Promise 化(如 util.promisify)才能被正确捕获;裸回调中的异常会逃逸为未捕获异常;Promise.all 遇拒即退,allSettled 则需手动检查结果。

async/await 本身不直接处理回调函数中的异常,而是通过 try/catch 捕获 await 表达式抛出的错误。关键在于:只有被 await 的 Promise 被 reject,错误才会进入 catch;而回调函数(如 setTimeout、Node.js 的 fs.readFile 回调)若未被 Promise 化,其内部异常不会自动被 try/catch 捕获。

确保回调函数被正确 Promise 化

原始回调函数(如 Node.js 的 err-first 风格)需封装为 Promise,才能让 await 和 try/catch 生效:

  • 用 Promise 构造器包装:将回调的 error 参数转为 reject,成功结果转为 resolve
  • 避免在回调里直接 throw —— 这只会触发未捕获异常,不会中断 await 流程
  • 推荐使用现成工具(如 util.promisify)或封装可复用的 promisify 函数

正确使用 try/catch 包裹 await 表达式

catch 只能捕获当前 await 所等待的 Promise 的 rejection,不是整个 async 函数体内的任意 throw:

  • 错误写法:await someAsync(); throw new Error('oops'); —— 这个 throw 不会被外层 catch 捕获,除非它发生在 await 后且没被处理
  • 正确写法:所有可能出错的异步操作都用 await,并置于 try 块中
  • 多个 await 可共用一个 try/catch,也可各自独立处理

注意非 Promise 回调的“幽灵异常”

如果在 async 函数里直接使用传统回调(比如 setTimeout(() => { throw 'boom' }, 100)),这个异常完全脱离 try/catch 作用域:

  • 它会变成未捕获异常(Uncaught Exception),可能 crash 进程或触发 unhandledrejection 事件
  • 解决方式:要么避免在 async 函数中裸写回调,要么手动用 try/catch 包裹回调内部逻辑(但不推荐,破坏 await 语义)
  • 更安全的做法是把所有异步逻辑统一转为 Promise 链

处理多个并发异步操作的异常

使用 Promise.allPromise.allSettled 时,异常行为不同:

  • Promise.all([p1, p2]):任一 Promise reject,整个 all 就 reject,可被外层 catch 捕获
  • Promise.allSettled([p1, p2]):总会 resolve,结果数组含每个 Promise 的 status 和 value/reason,需手动检查每个项是否 fulfilled
  • 若需部分失败仍继续,优先选 allSettled + 遍历结果判断

热门栏目