前端错误监控
实际工作中,无论是开发环境还是生产环境都不可避免的会产生错误,快速的找出错误、上报错误、及时修复错误非常重要,能减小或避免重大损失和客户流失。保证上线的产品质量也是说的错误监控,因为产品上线后,线上的代码错误如果都不能收集的话,如何保证产品质量呢。
1. 错误分类
前端错误通常可以分为代码错误(即时运行错误)和资源加载错误。
1.1. 代码错误
可以使用以下方式来捕获错误。
try-catch-finally
window.onerror
(或监听 window 的 error 事件)unhandledrejection
属性可以监听没有被 catch 的 promise 错误信息。- Vue 框架可以使用
errorCaptured
(生命周期钩子)监听下级组件报错,返回 false 阻止向上传播。 - Vue 框架可以使用
errorHandler
监听全局 Vue 组件报错。指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。
- try-catch-finally
这种方法只是适用于在风险比较高的地方捕获,因为很多地方都这样写成本太高。
try {
// 这里可能会产生错误
} catch(err) {
// err 接收到 try 块儿中的错误
} finally {
// TODO
}
- window.onerror
这种方法是一种全局的方法,能够捕获到大部分代码错误的场景。
window.onerror = function(message, source, colNum, rowNum, error) {
// 对于外部 JS ,如加载的 CDN ,则无法清楚知道哪里报错
// 对于线上被压缩过后的代码,也知不知道 colNum, rowNum,需要配合 sourcemap 来看。
}
- unhandledrejection
对于没有被 catch 的 promise 错误信息(异步错误),可以使用 window 监听 unhandledrejection 事件。
window.addEventListener('unhandledrejection', (error) => {
console.error('捕获到异步异常', error);
});
- errorCaptured
在捕获一个来自后代组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
(err: Error, vm: Component, info: string) => ?boolean
- errorHandler
errorHandler 指定一个处理函数,来处理组件渲染函数和侦听器执行期间抛出的未捕获错误。这个处理函数被调用时,可获取错误信息和相应的应用实例。
app.config.errorHandler = (err, vm, info) => {
// 处理错误
// `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
}
1.2. 资源加载错误
比如 CSS 、JS 、图片加载错误,可以使用以下方式来捕获错误。
- 对象的 onerror 方法
对象的 onerror 方法来捕获错误,比如图片 image.onerror。
function loadImage(src) {
return new Promise((resolve, reject) => {
const img = document.createElement("img");
img.alt = "promise方式加载的图片";
img.src = src;
img.onload = () => {
resolve(img);
};
img.onerror = () => {
const err = new Error("图片加载失败!");
reject(err);
};
});
}
- performance.getEntries()
根据发起的请求个数和成功的个数的一个比较,得出哪个请求出错了。
// 获取加载的资源的名称
// performance.getEntries() 返回一个数组
performance.getEntries().forEach(item => console.log(item.name))
上面代码返回成功加载的资源的名称,在和 network 面板请求的所有资源做一个对比,就能得出哪个(些)资源加载出错了。
- 捕获阶段监听 window 的 error 事件
资源加载错误,不会冒泡,所以无法直接通过 window.onerror 来捕获,但是可以通过监听 error 事件在捕获阶段来捕获。
window.onerror 只能捕获即时运行错误,对于资源运行错误没法捕获。
// 捕获阶段监听 error 事件
// 错误监控代码写在加载错误资源的前面
<script>
window.addEventListener("error", function(event) {
console.log("捕获资源加载错误", event);
}, true); // 第三个参数为 true 表示捕获阶段
</script>
<script src="https://www.baidu.com/xcvbnmkjhgf.html"></script> // 模拟一个没有的地址,模拟资源加载错误
2. 跨域的资源如何监控
上面介绍代码错误使用 window.onerror 来捕获时,如果是跨域的就没法知道错误的行号和列号,对代码错误的排查没有帮助,这时候就需要服务端配合了。
- 客户端加上
crossorigin
。 - 服务端响应头加上
Access-Control-Allow-Origin: *
。
加上上面两步处理后,就可以拿到跨域错误的代码的详细信息了。
3. 上报错误的基本原理或方法
- 通过 Image 对象上报,
(new Image()).src='xxxxxx'
,最简单也不需要借助第三方库。 - 通过 AJAX 通信上报。需要借助第三方库,比如 axios。
因为给 Image 对象附上 src 属性后,就会向服务器发送请求。这个时候 src 中可以携带我们需要上报的错误信息作为 search 部分传给服务端。