问题场景
线上用户反馈"页面白屏了",你本地怎么复现都不行;或者用户说"点按钮没反应",但你根本不知道报了什么错。没有错误监控的前端,就像蒙着眼睛开车------全靠用户当你的眼睛。
原因分析
前端错误主要分三类,捕获方式完全不同:
- 运行时错误 (同步/异步代码抛错)→
window.onerror - Promise 未捕获拒绝 →
unhandledrejection - 资源加载失败 (图片/脚本/CSS)→
error事件的捕获阶段
很多人只监听 window.onerror,结果 Promise 错误和资源错误全漏了。
完整监控方案
第一步:捕获运行时错误
js
window.onerror = function (message, source, lineno, colno, error) {
report({
type: 'runtime',
message,
source,
lineno,
colno,
stack: error?.stack,
url: location.href,
ua: navigator.userAgent,
time: Date.now()
});
// 注意:返回 true 会阻止浏览器默认处理(如控制台报错),慎用
};
第二步:捕获 Promise 错误(最容易漏)
js
window.addEventListener('unhandledrejection', (e) => {
// e.reason 可能是 Error 对象,也可能是任意值(如字符串、对象)
report({
type: 'promise',
message: e.reason?.message || String(e.reason),
stack: e.reason?.stack,
time: Date.now()
});
e.preventDefault(); // 可选:屏蔽控制台红色警告
});
第三步:捕获资源加载失败
js
// 必须用捕获阶段(第三个参数 true),因为资源错误不会冒泡
window.addEventListener('error', (e) => {
const target = e.target;
if (target && (target.tagName === 'IMG' || target.tagName === 'SCRIPT' || target.tagName === 'LINK')) {
report({
type: 'resource',
tag: target.tagName,
src: target.src || target.href,
time: Date.now()
});
}
}, true);
第四步:框架层兜底
Vue 3:
js
app.config.errorHandler = (err, instance, info) => {
report({ type: 'vue', message: err.message, stack: err.stack, info });
};
React: 用 Error Boundary 包裹,componentDidCatch 里上报。
第五步:上报策略(防刷爆后端)
js
// 采样 + 去重 + 批量
let buffer = [];
function report(data) {
buffer.push(data);
if (buffer.length >= 10) flush();
}
function flush() {
if (!buffer.length) return;
// 用 sendBeacon,页面关闭也能发出;且不阻塞主线程
navigator.sendBeacon('/api/error-report', JSON.stringify(buffer));
buffer = [];
}
window.addEventListener('beforeunload', flush);
// 采样:只上报 10% 的重复错误,控制成本
if (Math.random() > 0.1) return;
进阶技巧
- sourcemap 还原 :生产代码是压缩的,上报
error.stack后,用 sourcemap 在服务端还原原始行号(webpack 配devtool: 'hidden-source-map',map 文件不上传到 CDN) - 错误去重 :同一错误一天内只告警一次,按
message + source + lineno做指纹 - 白屏检测 :
document.readyState长时间非complete或document.body无子节点,主动上报
要点总结
- 三类错误三种捕获姿势:
onerror(运行时)、unhandledrejection(Promise)、捕获阶段error(资源) - 框架错误要用各自的钩子(Vue
errorHandler/ React Error Boundary) sendBeacon+ 批量上报,页面销毁也不丢数据- 采样、去重、指纹告警,否则监控系统会被错误洪流淹没
- sourcemap 只上线 map 文件到内网,别把源码泄露到 CDN