一、捕获的错误类型
- 语法错误
- 运行时异常
- 资源加载异常
- img
- script
- link
- audio
- video
- iframe
- ...外链资源的DOM元素
- 异步请求异常
- Promise异常
- CSS中资源异常
- font-face
- background-image
二、捕获方式
- try-catch
- window.onerror = cb (DOM0)
- window.addEventListener('error', cb, true) (DOM2)
- window.addEventListener("unhandledrejection", cb) (DOM4)
- Promise.then().catch(cb)
- 定制异步请求代码
三、错误上报相关问题
- 获取不到具体错误
- 跨域调用js,由于浏览器的安全策略,只会返回 Script error. ;通过添加crossorigin来解决; image 和 script 标签都有 crossorigin 参数,它的作用就是告诉浏览器,我要加载一个外域的资源,并且我信任这个资源;服务器也需要设置
Access-Control-Allow-Origin
的响应头; - 生产环境代码都被压缩打包,可以在打包代码时相应添加一些空格,虽然不能定位到具体位置,不过通过行数,可以获得具体哪个文件出了错,缩小排查范围;
- 跨域调用js,由于浏览器的安全策略,只会返回 Script error. ;通过添加crossorigin来解决; image 和 script 标签都有 crossorigin 参数,它的作用就是告诉浏览器,我要加载一个外域的资源,并且我信任这个资源;服务器也需要设置
- 收集的采样率
- 没有必要将所有的错误信息全部送到 Log 中,这个量太大了。如果网页 PV 有 1kw,那么一个必现错误发送的 log 信息将有 1kw 条,大约一个 G 的日志。我们可以给
Reporter
函数添加一个采样率;function needReport (sampling){ // sampling: 0 - 1 return Math.random() <= sampling; } Reporter.send = function(errInfo, sampling) { if(needReport(sampling || 1)){ Reporter._send(errInfo); } };
- 没有必要将所有的错误信息全部送到 Log 中,这个量太大了。如果网页 PV 有 1kw,那么一个必现错误发送的 log 信息将有 1kw 条,大约一个 G 的日志。我们可以给
- 尽量少的使用
try..catch,如果要使用请使用尽量干净的作用域;
- 错误的报警与提示
- 错误超过阈值,比如 10分钟最多允许 100 个错误,结果超过了 100
- 错误超过平均值的 10 倍,超过平均值就报警,这个逻辑显然不正确,但是超过了平均值的 10 倍,基本可以认定服务出问题了
- 在纳入对比之前,要过滤同 IP 出现的错误,比如一个错误出现在 for 循环或者 while 循环中,再比如一个用户在蹲点抢购,不停的刷新
- 上报方式
- 优点实现简单可跨域;
// 简单可跨域 function report() { (new Image()).src="http://post.error.com?data=xxx" }
进阶版,使用 Navigator.sendBeacon() -
// navigator.sendBeacon(url, data); navigator.sendBeacon('http://post.error.com', 'data=xxxxx'); // data 可以传递 string 类型,那么后端接口里接到的请求,Content-Type 为 text/plain,就当字符串处理data
// 此方法可用于满足统计和诊断代码的需要,可以批量发送数据,并且浏览器保证它不卡渲染线程,在页面 load/unload 事件里处理异步动作而不影响渲染,并且天然跨域。缺点只是兼容性了 - 兼容版
function reportData(url, data) { if (navigator.sendBeacon) { navigator.sendBeacon(url, data); } else { (new Image()).src = `${url}?data=${data}` } } export default reportData;
- 优点实现简单可跨域;
- 几种上报方法
-
window.addEventListener("error", function(e) { var eventType = [].toString.call(e, e); if (eventType === "[object Event]") { // 过滤掉运行时错误 // 上报加载错误 可以获取资源加载错误 console.log(ev.target); report(ev) } }, true );
-
-
window.onerror = function (msg, url, lineNo, columnNo, error) { // 捕捉错误 console.log(msg, url, lineNo, columnNo, error) }
-
window.addEventListener("unhandledrejection", function (event) { // 捕获违背catch的reject console.log(event) console.log(event.reason); event.preventDefault(); // window.addEventListener('error')捕获资源加载错误。因为它也能捕获js运行时错误,为避免重复上报js运行时错误,此时只有event.srcElement inatanceof HTMLScriptElement或HTMLLinkElement或HTMLImageElement时才上报 });
-
//window.onerror和window.addEventListener('error')的异同 //相同点是都可以捕获到window上的js运行时错误。 //区别是1.捕获到的错误参数不同 // 2.window.addEventListener('error')可以捕获资源加载错误,但是window.onerror不能捕获到资源加载错误
ps: 感谢巨人的肩膀使我们看的更远
- https://www.cnblogs.com/hustskyking/p/fe-monitor.html
- http://www.alloyteam.com/2015/09/explore-performance/
- https://segmentfault.com/a/1190000016959011
- https://blog.csdn.net/weixin_34202952/article/details/88833376