未捕获的 rejection 本质是 promise 拒绝后未被 await、.catch() 或 try/catch 拦截,会触发警告或进程退出;应分层设防:在可能失败的 await 处用 try/catch、并行任务用 promise.allsettled、全局监听 unhandledrejection 作兜底、封装 to 函数简化错误处理。

async/await 中未捕获的 rejection,本质是 Promise 被拒绝后没被 await、.catch() 或 try/catch 拦截,最终变成“未处理的拒绝”。它不会中断主线程,但会触发控制台警告,Node.js v15+ 甚至直接退出进程。处理关键不是靠一层兜底,而是分层设防。
在 await 处主动加 try/catch
这是最直接、最推荐的做法。只有 await 表达式本身能将 Promise rejection 转为可捕获的同步异常;不包在 try 里,错误就会上浮成未处理拒绝。
- 只包裹真正可能失败的 await,比如
await fetch()、await response.json() - 避免把整个 async 函数体全塞进一个 try —— 不利于定位哪一步出错
- catch 里建议记录
error.message和error.stack,必要时补上下文(如 URL、参数)
并行操作用 Promise.allSettled
多个无依赖的异步任务(如同时拉用户、权限、配置),别用串行 await 或 Promise.all —— 前者一错全停,后者一错全拒,都增加兜底压力。
-
Promise.allSettled返回每个任务的完整状态对象:{ status: 'fulfilled' | 'rejected', value | reason } - 后续可遍历结果,对失败项单独打日志、降级或聚合上报,不影响成功项
- 比每个 await 后手动 .catch() 更简洁,也比全局监听更精准
全局监听 unhandledrejection 作最后一道防线
再严谨的代码也可能漏掉某些路径:事件回调里的 async、定时器触发的异步、第三方库调用……全局监听能捕获所有漏网之鱼。
- 浏览器用
window.addEventListener('unhandledrejection', handler),Node.js 用process.on('unhandledRejection', (reason, promise) => {}) - 事件对象含
reason(拒绝值,可能是 Error、字符串等)和promise实例 - 适合做日志、监控上报(如 Sentry)、用户提示,但不要在此 throw 新错误或尝试恢复业务逻辑
封装工具函数降低 try/catch 噪声
把“错误即值”模式落地,让异步调用像同步一样可预测。例如写一个 to 函数:
const [err, data] = await to(fetch('/api/user'))- 成功时
err为 null,data是响应;失败时err是错误对象,data为 undefined - 避免重复写 try/catch,尤其适合组合式函数、API 封装层等高频调用场景










