unhandledrejection 仅是错误逃逸后的兜底通知机制,无法拦截或重写 await 行为;它发生在 promise 拒绝且未被 .catch() 或 try/catch 处理之后,仅可用于日志监控,不能改变已失败的 await 结果。

不能通过 unhandledrejection 事件“二级重写 await 逃逸报错”——这个说法本身存在根本性误解。
unhandledrejection 不是错误拦截器,而是兜底通知机制
unhandledrejection 是浏览器/Node.js 在 Promise 被 reject 且**没有任何地方调用 .catch() 或用 try/catch 捕获时**触发的全局事件。它发生在错误已经“逃逸”之后,仅用于日志、监控或降级处理,无法阻止错误发生,也不能改变 Promise 的状态或“重写 await 行为”。
例如:
window.addEventListener('unhandledrejection', e => {
console.log('被 reject 但没人管:', e.reason); // 只能看,不能“救”
e.preventDefault(); // 仅抑制控制台警告,不阻止错误语义
});
async function bad() {
await Promise.reject(new Error('boom')); // 这里 await 已失败,调用栈已退出
}
bad(); // 触发 unhandledrejection,但无法让这行 await “变成功”
真正可控的“逃逸拦截”必须在 await 执行前介入
想让某个 await 不抛出异常(即“逃逸”被抑制),必须在 Promise 被 await 之前就处理其 rejection。常见可靠方式有:
-
手动包裹 Promise:用
Promise.resolve(p).catch(() => undefined)或封装成safeAwait(p)函数,让 reject 转为 resolve 一个默认值 - 统一 try/catch 包裹 async 函数体:在业务入口或中间件层捕获,避免未处理的 reject 向上冒泡
- 使用运行时沙箱(如 SES)或代理层:在低层劫持 Promise 构造或 then/catch 调用(复杂且不推荐用于常规逻辑)
为什么不能靠 unhandledrejection “重写 await”
await 是 JavaScript 引擎语法,它的行为由 Promise 状态决定;unhandledrejection 是异步任务队列清空后才派发的事件,此时:
- await 对应的微任务早已完成或失败
- 所在函数的执行上下文已销毁
- 错误堆栈不可逆地终止了当前 async 函数流程
→ 没有机制能让该事件回调“回滚”或“改写”已发生的 await 结果。
实用建议:监控 + 防御性编程组合
把 unhandledrejection 当作报警器,而非修复器:
- 记录未处理 rejection 的 Promise 堆栈和上下文,快速定位漏掉
catch的位置 - 配合 ESLint 规则(如
no-promise-reject-errors)或 TypeScript 的 exhaustive check 提前发现风险 - 对关键 await 调用强制要求显式处理:
await p.catch(handleError)或封装await safe(p, fallback)











