try-catch仅捕获同步错误,对setTimeout、Promise等异步错误无效;Promise需用.catch或await+try-catch;全局错误用window.addEventListener('error')和'unhandledrejection'监听。

JavaScript 错误捕获的核心:try-catch 只能捕获同步错误
直接说结论:try-catch 对异步代码(比如 setTimeout、fetch、Promise.then)里的错误完全无效。很多人写完 try-catch 还是看到 Uncaught Error,就是因为把异步逻辑塞进了 try 块里,却没意识到执行时机已脱离当前调用栈。
真正能被 try-catch 捕获的,只有「立即执行且抛出异常」的同步代码,比如:
try {
JSON.parse('{ "name": }'); // 语法错误 → 被捕获
} catch (err) {
console.log(err.message); // Unexpected token } in JSON at position 12
}
Promise 错误不能靠外层 try-catch,得用 .catch 或 await + try-catch
Promise 的 reject 不会触发外层 try-catch,哪怕它写在 try 块里。这是最常踩的坑。
- ❌ 错误写法(不会捕获):
try { Promise.reject(new Error('boom')); } catch (e) { console.log('never runs'); } - ✅ 正确写法一(链式
.catch):Promise.reject(new Error('boom')) .catch(err => console.log(err.message)); - ✅ 正确写法二(
async/await+try-catch):async function run() { try { await Promise.reject(new Error('boom')); } catch (err) { console.log(err.message); // boom } }
全局错误兜底:window.onerror 和 window.addEventListener('error')
当错误逃逸到最外层(比如事件回调、定时器、未处理的 Promise reject),try-catch 就无能为力了,这时需要全局监听。
立即学习“Java免费学习笔记(深入)”;
-
window.onerror能捕获 JS 运行时错误和资源加载失败(如 script 404),但无法拿到error实例的完整堆栈(部分信息被截断); -
window.addEventListener('error')类似,但更通用,推荐优先用它; - 未处理的 Promise 拒绝必须用
window.addEventListener('unhandledrejection')单独监听,否则会直接打印 “Uncaught (in promise)” 并终止进程(开发环境尤其明显)。
示例:
window.addEventListener('unhandledrejection', event => {
console.warn('Unhandled rejection:', event.reason);
event.preventDefault(); // 阻止控制台默认报错(仅开发调试时慎用)
});
实际项目中该在哪加 try-catch?别乱套
不是所有地方都适合加 try-catch。滥用反而掩盖问题、干扰调试。
- 适合加:JSON 解析、
localStorage.setItem(可能因配额超限失败)、第三方 SDK 的同步调用(如analytics.track()); - 不适合加:纯计算逻辑(如
a + b)、已知安全的 DOM 操作(如el.classList.add)、没有 throw 可能的函数; - 注意
catch后必须处理错误——至少打日志,否则等于静默吞错; - 不要只写
catch (e) { },至少保留console.error(e)或上报错误服务。
复杂点在于:错误边界往往不在语法层面,而在业务语义层面。比如「用户提交表单失败」是预期流程,不该算 JS 错误;而「解析后端返回的 JSON 字段缺失」才是真异常——这需要你判断哪里是「可控失败」,哪里是「意外崩溃」。











