try-catch只捕获同步异常,如throw、TypeError等;异步错误需用async/await或unhandledrejection监听;window.onerror和error事件补全局错误,但Web Worker、跨域iframe等错误无法捕获。

try-catch 能捕获哪些错误?
它只捕获**同步执行中抛出的异常**,比如 throw new Error()、类型错误(TypeError)、引用错误(ReferenceError)等。异步代码(如 setTimeout、fetch、Promise 回调)里直接 throw,不会被外层 try-catch 捕获。
常见误判场景:
- 写了
try { fetch('/api').then(...)} catch(e) {...}—— 这个catch实际捕获不到 Promise 内部错误 -
JSON.parse('invalid')会触发,但JSON.parse(undefined)也会(因为传了非字符串) - 箭头函数中忘记写
return,导致意外返回undefined,后续调用.map报TypeError: Cannot read property 'xxx' of undefined—— 这类错误能被捕获,但根源在逻辑,不是语法
async/await 怎么配合 try-catch?
这是目前最接近“同步写法捕获异步错误”的方式。关键点:await 必须在 async 函数内,且被 await 的 Promise 被 reject 时,会以异常形式抛出,进 catch 块。
正确写法示例:
立即学习“Java免费学习笔记(深入)”;
async function loadData() {
try {
const res = await fetch('/api/users');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
return data;
} catch (err) {
console.error('加载失败:', err.message);
// 这里能捕获 fetch 网络失败、JSON 解析失败、手动 throw 的错误
}
}
注意:
- 不要对
fetch本身加 try-catch 就以为万事大吉 —— 它只拒绝网络级错误(如离线),404、500仍返回成功 Promise,需手动检查res.ok -
await Promise.reject(new Error())会被捕获;但Promise.reject()不 await,就不会
window.onerror 和 window.addEventListener('error') 有什么区别?
它们补的是 try-catch 漏掉的“全局异常”:脚本加载失败、资源加载错误( 404)、未捕获的 Promise rejection、跨域脚本错误(此时 error 信息被浏览器抹为 Script error.)。
实操建议:
- 用
window.addEventListener('error', handler)捕获资源加载类错误(如图片、CSS 加载失败),它比window.onerror更早触发,且能拿到event.target - 必须同时监听
unhandledrejection事件来捕获没被 catch 的 Promise 错误:
window.addEventListener('unhandledrejection', event => {
console.error('未处理的 Promise 拒绝:', event.reason);
event.preventDefault(); // 阻止默认控制台报错(可选)
});
注意:unhandledrejection 在 Promise 被 reject 且没有 .catch 或 await 后无 try-catch 时才触发 —— 不是所有 reject 都算“未处理”。
为什么有些错误就是抓不到?
根本原因在于 JavaScript 错误分类和运行时机制。以下几类基本无法用常规 JS 错误处理捕获:
-
console.error()不是错误,只是日志,不会触发任何异常机制 - Web Worker 内部错误不会冒泡到主页面,需在 worker 内单独监听
onerror - iframe 中的脚本错误受同源策略限制,跨域 iframe 的错误信息不可读(只显示
Script error.) - 某些浏览器扩展注入的脚本崩溃、或页面被强制 kill(如 iOS Safari 内存回收)—— 这些已脱离 JS 执行上下文
真正容易被忽略的点:错误对象的 stack 属性在压缩后可能指向混淆后的文件行号,上线前确保 source map 正确上传并被监控平台识别。否则你看到的 at a.js:1:1 没有任何调试价值。











