异步错误处理需按认知阶梯分层:先理解同步try/catch捕获不到异步错误的本质是执行时机问题,再掌握Promise链、async/await、回调等场景的对应捕获方式,最后通过工具和习惯固化实践。

JS 异步错误处理不能靠零散试错,得按认知阶梯一层层来:先理解“为什么同步 try/catch 抓不住异步错误”,再掌握每种异步模式对应的捕获方式,最后在真实场景中建立判断习惯。
搞懂异步错误的本质——不是语法问题,是执行时机问题
传统 try/catch 只能捕获当前调用栈里抛出的错误。而 Promise reject、setTimeout 回调、fetch 失败这些,实际发生在事件循环后续阶段,原始调用栈早已清空。这就是为什么写成这样会失效:
❌ 错误示范:
try {
fetch('/api/data').then(res => res.json());
} catch (e) {
// 永远进不来
}
关键要意识到:错误没消失,只是没被当前上下文捕获。你需要把错误“拉回”可控的执行流里。
按异步写法分场景掌握捕获方式
不同写法对应不同处理惯式,混用容易漏错:
- Promise 链式调用:统一在末尾加 .catch(),它能穿透整个链(包括中间 then 里抛出的错误);避免每个 then 后都写 catch,除非需要局部处理并继续传播
- async/await:用 try/catch 包裹 await 表达式,一个 try 可捕获多个 await;注意 await 后面必须是 Promise,否则 catch 不生效
- 回调函数(如 Node.js 原生 API):严格遵循 error-first 模式,第一个参数恒为 err,必须显式判断 if (err) throw err 或处理
- 全局兜底:浏览器加 window.addEventListener('unhandledrejection'),Node.js 加 process.on('unhandledRejection'),只用于日志和告警,不能替代主动捕获
从简单请求到复杂流程,逐步叠加处理粒度
别一上来就写全链路重试 + 降级 + 监控。按项目复杂度递进:
- 单个 fetch 请求:用 async/await + try/catch,错误时给用户明确提示
- 多个并行请求:用 Promise.allSettled() 替代 Promise.all,确保一个失败不影响其余结果;再逐个检查 status 字段做差异化处理
- 带清理逻辑的异步操作(如打开文件后必须关闭):在 try 中执行主逻辑,在 finally 中做清理,无论成功失败都执行
- 需要自动重试的接口:封装 retry 函数,内部用 setTimeout 控制间隔,用计数器限制次数,失败最终仍需抛出供上层决策
用工具固化正确习惯
人会疏忽,但配置不会:
- 在 ESLint 中启用 no-floating-promise 规则,强制所有 Promise 必须被 await 或 .catch(),避免“忘了处理”
- 写完异步函数立刻补上错误分支,哪怕只是 console.error —— 先有形,再优化
- 本地调试时,在浏览器控制台开启 “Pause on caught exceptions”,能直观看到哪些错误被 try/catch 接住了,哪些穿透出去了


















