对于前端来说,往往是用户反馈了才知道已经错了。
为了让前端也能和后端一样,需要将线上的 JavaScript 代码监控起来,当用户端浏览器出现异前端第一时间被通知到。
主要原则就是避开用户敏感字段,采集浏览器版本、操作系统版本、报错的 msg 信息等。
前端错误大体上可以分成两类,
try {
init();
// code...
} catch(e){
Reporter.send(format(e));
}
try-catch是最弱鸡的, 缺点是
try... catch
包裹,影响代码可读性。 try {
var error = 'error'; // 中文输入法的;
} catch(e) {
console.log('我感知不到错误');
console.log(e);
}
try {
setTimeout(() => {
error // 异步错误
})
} catch(e) {
console.log('我感知不到错误');
console.log(e);
}
window.onerror要强那么一丢丢。无论是异步还是非异步错误,onerror 都能捕获到运行时错误。
/**
* @param {String} errorMessage 错误信息
* @param {String} scriptURI 出错的文件
* @param {Long} lineNumber 出错代码的行号
* @param {Long} columnNumber 出错代码的列号
* @param {Object} errorObj 错误的详细信息,Anything
*/
window.onerror = function(errorMessage,
scriptURI,
lineNumber,
columnNumber,
errorObj) {
// code..
}
window.onerror 的缺点:
window.addEventListener 可以监听到资源加载报错,也可以注册多个事件处理函数。
var fn = window.onerror = function() { // 只能监听到js执行的错误,无法监听资源加载的错误
console.log(arguments);
};
window.addEventListener("error", fn); // 可以监听到js执行的错误,和资源加载的错误
window.addEventListener("error", fn);
为捕获状态时(第三个参数为true)能捕获到js执行错误,也能捕获带有src的标签元素的加载错误。
为冒泡状态时(第三个参数为false)能捕获到js执行错误,不能捕获带有src的标签元素的加载错误。
promise 的报错比较娇贵,try ……catch
, window.onerror
, widow.addEventlistener
都无法监听到promise 的报错。
promise
中的报错顺序是:
window.addEventListener('unhandledrejection')
来处理。App({
onError(msg) {
this.monitor.onError(msg);
},
})
微信小程序代码中没有办法获取到window对象,自然不能用window.onError, 小程序官方提供了 app.onError的方法。
生产环境的代码是 webpack 混淆打包之后,不好定位。
解决办法是开启webpack
的source-map
,我们利用webpack
打包后的生成的一份.map
的脚本文件就可以让浏览器对错误位置进行追踪了。
var path = require('path');
module.exports = {
devtool: 'source-map',
mode: 'development',
entry: './client/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'client')
}
}
捕获资源加载失败的方法,主要如下:
一般来说,大厂都是采用利用image对象的方式上报错误的;使用图片发送get请求,上报信息,由于浏览器对图片有缓存,同样的请求,图片只会发送一次,避免重复上报。
var entry = {};
function report(url, data) {
if (!url || !data) {
return;
}
// @see http://jsperf.com/new-image-vs-createelement-img
var image = document.createElement('img');
var items = [];
for (var key in data) {
if (data[key]) {
items.push(key + '=' + encodeURIComponent(data[key]));
}
}
var name = 'img_' + (+new Date());
entry[name] = image;
image.onload = image.onerror = function () {
console.log(arguments);
entry[name] =
image =
image.onload =
image.onerror = null;
delete entry[name];
};
image.src = url + (url.indexOf('?') < 0 ? '?' : '&') + items.join('&');
}
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8