try-catch仅捕获同步执行流中的异常,无法捕获setTimeout或Promise.then等异步回调中的错误,因其运行在新执行上下文,原try块已退出;但配合await使用时,可将Promise拒绝转为同步异常而被捕获。

try-catch 本身不能直接捕获异步代码中的错误,但它在特定结构下可以有效处理异步异常——关键不在语法本身,而在执行时机与上下文是否匹配。
为什么普通 try-catch 抓不住 setTimeout 或 Promise.then 中的错误
核心原因是 JavaScript 的执行模型:try-catch 只监控当前调用栈内的同步执行流。一旦进入宏任务(如 setTimeout)或微任务(如 Promise.then),回调函数会在新执行上下文中运行,此时原 try 块早已退出,catch 失去作用域。
- setTimeout 回调抛错 → 触发全局 Uncaught Error
- Promise.resolve().then(() => { throw new Error() }) → 触发 Uncaught (in promise) Error,不进外层 catch
- fetch 返回 500 响应 → 不抛异常,仅返回 status=500 的 Response 对象,需手动检查 res.ok
哪些异步场景下 try-catch 确实能生效
当异步操作被 await 暂停并纳入 async 函数的执行流时,错误就能被同一 try-catch 捕获。本质是 await 将 Promise 的 reject 转换为同步风格的异常抛出。
- await fetch(url) 失败(网络中断、CORS)→ 进 catch
- await res.json() 解析非法 JSON → 抛 SyntaxError,进 catch
- async 函数内同步代码出错(如 undefined.xxx 或 throw new Error())→ 同样进 catch
常见误用与绕过方案
混合写法容易漏错,比如在 try 块里调用 Promise 链却不 await,或在 .then 中抛错却没配 .catch。这类情况必须统一收口。
- ❌ 错误:
try { api().then(x => x.data) } catch(e) { }—— 无法捕获 then 内异常 - ✅ 正确:
try { const res = await api(); return res.data; } catch(e) { } - ✅ 补充兜底:
Promise.reject().catch(handleError)或全局监听 unhandledrejection 事件
不是所有“看起来异步”的地方都需要 try-catch
有些操作天然不抛错,强行包裹反而掩盖问题或影响性能:
- localStorage.setItem() 即使配额满也不抛异常,后续操作才可能失败
- JSON.stringify() 在绝大多数输入下不会出错,但 JSON.parse() 必须 try
- 高频函数中滥用 try-catch 会禁用 V8 优化,优先用可选链(obj?.a?.b)或类型判断替代


















