近日腾讯音乐电话面试提到如何监控前端代码报错,涉及 js 代码报错,异步报错,图片资源、js资源加载报错,Promise报错如何进行监控统计,答的不够全面,于是仔细研究下。
- js 代码报错
- 异步报错
- 图片请求报错
- script src 资源加载报错
- Promise reject 或者 抛错
JS 异常处理
使用 try...catch...
try {
w
}catch(e){
console.log(e) // ReferenceError: w is not defined
}
异步处理
对于异步报错,使用try catch是无法捕捉到错误的,因为异步事件已经放入事件队列中,无法捕捉到。
于是可以采用在异步回调函数里面进行 try catch,如果有若干个异步事件都要进行 try catch就会比较繁琐,后面会介绍。
try {
setTimeout(() => {
err
}, 10);
} catch (error) {
console.log(error); // 并不会打印
}
图片请求
针对单个图片请求报错可以调用 Image 对象提供的api onerror回调函数进行错误捕获,那如果是很多图片呢?或者是其他的资源请求不到呢?
const img = new Image();
img.src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
img.onload = () => {
document.body.appendChild(img);
};
img.onerror = () => {
document.body.appendChild(new Text("Could not load the nebula :("));
};
Promise异常处理
通过 Promise 可以帮助我们解决异步回调地狱的问题,但是一旦 Promise 实例抛出异常而你没有用 catch 去捕获的话,onerror 或 try-catch 也无能为力,无法捕捉到错误,像如下示例报错:
Promise.reject('promise error');
new Promise((resolve, reject) => {
reject('promise error');
});
new Promise((resolve) => {
resolve();
}).then(() => {
throw 'promise error'
});
可以使用 window.addEventListener unhandledrejection
事件
MDN:
当Promise
被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection
事件
window.addEventListener("unhandledrejection", event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
// Prevent the default handling (such as outputting the error to the console
event.preventDefault();
});
Promise.reject('promise error');
new Promise((resolve, reject) => {
reject('promise error');
});
new Promise((resolve) => {
resolve();
}).then(() => {
throw 'promise error'
});
全局异常捕获 window.onerror
在MDN上是这么介绍的
- 当JavaScript运行时错误(包括语法错误)发生时,
window
会触发一个ErrorEvent
接口的error
事件,并执行window.onerror()
。 - 当一项资源(如
<img>
或<script>
)加载失败,加载资源的元素会触发一个Event
接口的error
事件,并执行该元素上的onerror()
处理函数。这些error事件不会向上冒泡到window,不过(至少在Firefox中)能被单一的window.addEventListener
捕获。 - 若该函数返回
true
,则阻止执行默认事件处理函数(window.addEventListener('error', function(event) { ... }))。
window.onerror = function (msg, url, lineNo, columnNo, error) {
var string = msg.toLowerCase();
var substring = "script error";
if (string.indexOf(substring) > -1){
alert('Script Error: See Browser Console for Detail');
} else {
var message = [
'Message: ' + msg,
'URL: ' + url,
'Line: ' + lineNo,
'Column: ' + columnNo,
'Error object: ' + JSON.stringify(error)
].join(' - ');
alert(message);
}
return false;
};
error
需要注意的是:
- window.onerror 事件必须写在代码运行之前,如果 写在执行代码之后,JS 代码执行报错了,就不会继续捕获到 window.onerror 事件了。
- window.onerror 是无法捕获到网络异常的错误
也可以通过 window.addEventListener('error') 进行捕获错误。
如下示例请求图片资源失败,由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,于是window.addEventListener 设置为 true 在捕获阶段进行
<img src="./1.png">
<img src="./2.png">
<img src="./3.png">
<img src="./4.png">
<script>
window.addEventListener('error', (event) => {
console.log(
event
);
}, true);
</script>
js 资源加载失败也同图片一样,错误事件监听事件要提前。
<script>
window.addEventListener('error', (event) => {
console.log(
event
);
}, true);
</script>
<script src="12.js"></script>
特别的,如果 A 网站使用 B(CDN) 域名下的js资源,但是JS执行报错了,浏览器只会给出 Script error 错误提示,不会有具体报错信息,原因是:浏览器的同源策略限制。
为了能够将CDN的报错信息显示出来,可以做如下操作:
1、A网站的服务端配置:Access-Control-Allow-Origin: b.com
2、A网站前端配置如下:
// http://a.com/index.html
<script>
window.onerror = function (error) {
console.log(error)
return true
};
</script>
<script src="http://b.com/test.js" crossorigin></script>
更强悍的前端异常监控可以看下 Sentry