在 async 函数中须用 try catch 显式捕获 await 抛出的错误,避免 unhandledrejection;独立异步操作优先用 promise.allsettled;全局监听 unhandledrejection 作为兜底;可用 to 函数实现“错误即值”简化流程。

在 async 函数中处理潜在的异步运行时错误,核心是主动拦截 Promise 拒绝,而不是依赖默认行为。错误不会中断主线程,但若未被处理,会变成静默丢失的 unhandledrejection,影响调试和线上稳定性。
必须在 await 处用 try catch 显式包裹
async 函数返回 Promise,await 是触发点,错误只在 await 执行时抛出,且仅能被同一函数内、该 await 行上方的 try catch 捕获。
- 只包裹真正可能失败的 await,例如
await fetch(url)或await response.json(),避免整函数套一个 try - catch 中至少记录
error.message和error.stack,关键请求建议补上 URL、参数、时间戳等上下文 - 不要在 catch 里空 return 或忽略错误——除非业务明确允许降级,否则应抛出、重试或返回有意义的 fallback 值
多个独立异步操作,优先用 Promise.allSettled
当几个请求互不依赖(如同时拉取用户信息、订单列表、系统配置),不应串行 await,也不该用 Promise.all(一个失败全崩)。
- 改写为:
const results = await Promise.allSettled([fetchUser(), fetchOrders(), fetchConfig()]) - 遍历 results,对每个
{ status: 'fulfilled' | 'rejected', value | reason }分别处理 - 失败项可单独上报、重试或填默认值,其余成功结果不受影响
加一层全局兜底:监听 unhandledrejection
即使写了 try catch,仍可能漏掉事件回调、定时器触发的 async、第三方 SDK 内部调用等路径。
- 应用初始化时注册:
window.addEventListener('unhandledrejection', e => { /* 上报 e.reason */ }) - 生产环境务必把
e.reason发送到监控系统(如 Sentry),附带页面路径、用户 ID、UA 等信息 - 它不是替代方案,而是最后一道防线——不能省略业务层的主动捕获
进阶:用 to 函数实现“错误即值”模式
当单个 async 函数内有大量细粒度 await(比如连续校验、转换、保存),反复写 try catch 会让逻辑支离破碎。
- 引入轻量包装函数:
const [err, data] = await to(fetch('/api/user')) - err 存错误对象,data 存响应值;后续直接
if (err) { ... }判断,流程更线性 - 源码通常不到 20 行,可自行封装,无需引入额外包











