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

热门教程

怎么在全局未捕获异常网关中通过 unhandledrejection 拦截逃逸的 async 报错

时间:2026-06-24 09:40:45 编辑:袖梨 来源:一聚教程网

unhandledrejection 是标准事件机制,用于兜底未处理的 Promise 拒绝;浏览器用 window.addEventListener('unhandledrejection'),Node.js 用 process.on('unhandledRejection');能捕获 async 抛错或 Promise.reject() 未 catch 的情况,不能捕获同步错误或已处理 Promise。

直接在应用启动时注册 unhandledrejection 监听器,就能捕获那些没被 try/catch.catch() 拦住的 async 函数内部错误。它不是“网关”,而是一个标准的浏览器/Node.js 事件机制,专为兜底漏掉的 Promise 拒绝设计。

浏览器端:用 window.addEventListener 注册监听

这是最常用也最稳妥的方式,必须尽早执行(比如在 <head> 中或入口 JS 第一行):

  • 监听事件类型为 'unhandledrejection'
  • 事件对象包含 event.reason(拒绝值,通常是 Error 实例)和 event.promise(出问题的 Promise)
  • event.preventDefault() 可抑制浏览器控制台的黄色警告,但不影响其他监听器运行

Node.js 端:用 process.on 替代

v15+ 版本中未监听会直接崩溃,所以必须显式处理:

  • 使用 process.on('unhandledRejection', (reason, promise) => { ... })
  • 建议同时监听 'rejectionHandled',用于发现“延迟补 catch”的情况
  • 不能靠这个恢复业务逻辑,只适合日志、上报、告警

它能抓到什么,不能抓到什么

明确边界才能避免误用:

  • 能捕获:async 函数里 throw new Error() 但没被外层 try/catch 包裹的情况;Promise.reject() 后没接 .catch()await 的场景
  • 不能捕获:同步错误(要用 window.onerror)、已处理的 Promise(哪怕晚几毫秒加 .catch() 就不算“未处理”)、跨域脚本错误、资源加载失败、框架内部封装过的错误(如 Vue 渲染异常)
  • reason 不一定带完整堆栈,尤其当 reject 值是字符串或普通对象时,所以优先在 async 内部做 try/catch

别把它当万能兜底,而是最后一道防线

真正健壮的做法是分层防御:

  • 业务层:每个 await 都配 try/catch,按错误类型做不同响应(重试、降级、提示)
  • 框架层:配合 Sentry、Bugsnag 等工具自动采集 unhandledrejection 并关联用户行为
  • 全局层:仅用于报警、统计、防止静默失败,不建议在这里 throwreject 新 Promise

热门栏目