try-catch 本身不能捕获异步错误,仅作用于同步执行上下文;async/await 是语法糖,通过将 promise 拒绝转译为同步异常使 catch 可捕获;settimeout、promise.then、事件回调等脱离当前执行流的错误仍无法被捕获。

try-catch 本身不能捕获异步错误,它只对同步执行上下文中的异常有效。所谓“能捕获异步错误”,其实是 async/await 与 try-catch 协同工作的结果,不是 try-catch 自身能力的扩展。
为什么原生 try-catch 抓不住 setTimeout 或 Promise.then 中的错误
根本原因在于 JavaScript 的事件循环机制和执行上下文生命周期:
- 异步任务(如 setTimeout 回调、Promise.then)被推入任务队列,等当前调用栈清空后才执行;
- try-catch 块在同步代码执行完就退出,对应的执行上下文和错误监听机制已销毁;
- 当异步回调真正运行并 throw 错误时,已脱离任何 try 块的保护范围,错误变成未捕获异常(Uncaught Error 或 Unhandled Rejection)。
async/await 是如何让 try-catch “看起来”能捕获异步错误的
await 并非让 try-catch 变成异步监听器,而是通过语言层面的语义转换实现错误捕获:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- async 函数返回 Promise,await 会暂停函数执行,并将后续逻辑自动编译为 Promise 链的 .then() 和 .catch();
- 当 await 后的 Promise 被 reject,V8 引擎会在内部将其转译为一个同步抛出的错误(等价于 throw),从而触发最近的 catch 块;
- 这个过程由 ECMAScript 规范保证(2017+),本质是语法糖,底层仍依赖 Promise.prototype.catch 的错误传播机制。
哪些异步错误依然无法被 try-catch 拦截
即使用了 async/await + try-catch,以下场景仍超出其作用边界:
- 全局未处理的 Promise rejection:比如顶层 await 失败但没用 try 包裹,或 Promise 链漏写 .catch;
- 事件处理器中的错误:如
img.onerror = () => { throw new Error(...) },回调是独立执行上下文; - 定时器回调(setTimeout/setInterval)、Web Worker 内部、跨域脚本抛出的错误——它们完全脱离当前 JS 执行流。
实际项目中推荐的错误捕获组合方案
单一 try-catch 不足以覆盖所有异常场景,需分层兜底:
- 业务逻辑层:用 async/await + try-catch 处理可预期的异步失败(如 fetch 请求、JSON 解析);
- 资源加载层:用
window.addEventListener('error')捕获 script/img 等资源加载失败; - 全局兜底层:用
window.addEventListener('unhandledrejection')捕获漏掉的 Promise 拒绝; - 注意:fetch 返回的 HTTP 错误(如 404、500)默认不会 reject,需手动检查
res.ok并 throw。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










