监听 window.onerror 为啥收不到异步错误?

码农冠英 阅读 28

我在项目里加了全局错误监控,用的是 window.onerror,同步的报错都能捕获到,但像 setTimeout 里的错误就收不到了,这是为啥?

我试过这样写:

window.onerror = function(msg, url, line, col, error) {
  console.log('捕获到错误:', error);
  return true;
};

setTimeout(() => {
  throw new Error('异步错误测试');
}, 100);

结果控制台报错了,但 onerror 根本没触发,是不是异步错误得用别的方法监听?

我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
FSD-春艳
这是个老坑了,window.onerror 对异步代码(setTimeout、Promise等)的捕获能力确实有限,不同浏览器表现还不一样。

直接说结论:用 window.addEventListener('error') 配合 window.addEventListener('unhandledrejection') 才是正解。

代码给你:

// 捕获同步错误和 setTimeout 等异步错误
window.addEventListener('error', (event) => {
console.log('捕获到错误:', event.message);
// 阻止控制台报错
event.preventDefault();
});

// 捕获 Promise 未处理的 rejection
window.addEventListener('unhandledrejection', (event) => {
console.log('捕获到 Promise 错误:', event.reason);
event.preventDefault();
});

// 测试 setTimeout
setTimeout(() => {
throw new Error('setTimeout 错误');
}, 100);

// 测试 Promise
Promise.reject('Promise 错误');

// 测试同步错误
// throw new Error('同步错误');


说下区别在哪。用 window.onerror = function 的方式其实是在覆盖 onerror 属性,只能绑定一个处理函数,而且某些场景下事件对象信息不全。用 addEventListener 可以绑定多个监听,事件对象里信息更完整,对异步错误的支持也更稳定。

另外要注意,如果你的 JS 文件是跨域加载的,记得给 script 标签加 crossorigin 属性,否则错误信息会被浏览器吃掉,只能拿到 Script error. 这种没用的提示,这个坑踩的人特别多。
点赞 1
2026-03-01 18:17
公孙梓童
当时我也卡在这,以为是监听时机不对或者写法有问题,后来翻了下规范才发现:window.onerror 只能捕获当前执行栈里的同步错误,而 setTimeout 里的代码是在新的执行栈里执行的,它的错误不会冒泡到外层的 onerror 去。

要捕获异步错误,得用 window.addEventListener('error', handler, true),而且得用捕获阶段(第三个参数设为 true),因为冒泡阶段的 error 事件在 window 层级可能已经被拦截或丢失了。

你改成这样试试:

window.addEventListener('error', function(e) {
console.log('捕获到错误:', e.error);
// e.message, e.filename, e.lineno, e.colno 也能拿到
return true;
}, true);

setTimeout(() => {
throw new Error('异步错误测试');
}, 100);


注意,Promise 的 unhandledrejection 得单独监听 window.onunhandledrejection 或 addEventListener('unhandledrejection'),这个跟 error 事件是两套体系,别混了。

对了,IE 里老版本不支持 addEventListener,但那会儿也基本没人用 window.onerror 做监控了,现在基本都是现代浏览器,放心用 addEventListener('error', ..., true) 就行。
点赞 2
2026-02-25 23:06