async函数中未捕获的错误本质是未处理的Promise拒绝,需在await处用try catch拦截;并行操作宜用Promise.allSettled;全局监听unhandledrejection作兜底;进阶可用to函数实现“错误即值”模式。

async 函数里抛出的未知错误,本质是 Promise 被拒绝(rejected)时未被处理的异常。它不会中断主线程,但若没捕获,会变成未处理的 Promise 拒绝,可能静默丢失、影响调试,甚至在生产环境触发 unhandledrejection 事件。
必须在 async 函数内部用 try catch 包 await 行
外部 try catch 无法捕获 await 抛出的错误,因为 async 函数返回的是 Promise,错误发生在异步阶段,不是同步执行流。只有在函数体内对具体 await 表达式做包裹,才能真正拦截。
- 只包裹实际可能失败的 await 调用,比如
await fetch(...)或await response.json() - 避免把整个函数体全包进一个 try —— 会掩盖逻辑分界,也不利于错误定位
- catch 块中建议至少记录 error.message 和 error.stack,必要时补充上下文(如请求 URL、参数)
多个独立异步操作:用 Promise.allSettled 避免连锁中断
当几个 await 之间没有依赖关系(比如并行拉取用户、订单、配置),单个失败不该让其余也停摆。此时不应串着写 await,而该合并发起。
-
Promise.allSettled返回每个 Promise 的结果(fulfilled/rejected),不会因一个失败而中断全部 - 后续可遍历结果,分别判断 status,对失败项单独处理或汇总上报
- 比
Promise.all更健壮,适合容错场景
兜底防御:监听 unhandledrejection 防止错误丢失
即使写了 try catch,仍可能漏掉某些路径(比如事件回调里的 async、定时器触发的 async、第三方库调用)。全局监听能捕获所有未被处理的 Promise 拒绝。
- 在应用初始化时注册:
window.addEventListener('unhandledrejection', e => { console.error('Unhandled rejection:', e.reason); }) - 生产环境建议将
e.reason上报至监控系统(如 Sentry),带上页面路径、用户 ID 等上下文 - 注意:该事件不替代具体业务层的错误处理,而是最后一道防线
进阶选择:用 to 函数实现“错误即值”风格
如果项目中大量出现细粒度错误处理(比如每个 await 后都要判错再决定流程),try catch 会显得冗长。可引入类似 await-to-js 的轻量包装:
- 调用形式为
const [err, data] = await to(fetch(...)),错误走 err,成功走 data - 无需写 catch 块,逻辑更线性,适合状态驱动或条件分支多的场景
- 源码极简(通常十几行),可自行封装,不依赖额外包


















