最近一直在做前端js错误监控的工作,在不断的打磨和完善中,发现里面还是知识点不少,现在就前端js错误监控做一些笔记和总结
为什么要做前端错误监控?
为了保证产品的质量
有些问题只存在于线上特定的环境
后端错误有监控,前端错误没有监控
下面会讲:
- 前端错误的分类
- 错误的捕获方式
- 上报错误的基本原理
一. 前端错误的分类
- 即时运行错误:代码错误
- 资源加载错误:(js、css、图片加载失败)
二. 错误的捕获方式
- 即时运行错误的捕获方式
- try….catch
- window.onerror
- 资源加载错误的捕获方式
- object.onerror
- performance.getEntries
- Error事件捕获
1.即时运行错误的捕获方式
1.try…catch
通过try…catch我们能够知道出错的信息,并且也有堆栈信息可以知道在哪个文件第几行第几列发生错误。
1 | try { |
缺点:
- 没法捕捉try,catch块,当前代码块有语法错误,JS解释器压根都不会执行当前这个代码块,所以也就没办法被catch住;
- 没法捕捉到全局的错误事件,也即是只有try,catch的块里边运行出错才会被你捕捉到,这里的块你要理解成一个函数块
2.window.onerror
全局捕获。window.onerror
会在页面发生js错误时被调用可以收集到错误字符串信息、发生错误的js文件,错误所在的行数、列数、和Error对象(里面会有调用堆栈信息等),还可以在window.onerror最后return true让浏览器不输出错误信息到控制台
1 | /* |
3.object.onerror
img、script标签都可以添加onerror事件,当资源请求失败的时候,都会触发该事件。
1 | var img = document.getElementById('img'); |
4.performance.getEntries
performance是h5的新特性之一,使用该方法能获取到当前页面已经加载到的资源,返回的是一个数组对象。
例子获取页面中没有成功加载的图片资源?
1 | let arr = [], |
控制台使用: var arr=[]; performance.getEntries().forEach((item,i)=>{console.log(arr[i]=item.name)})
打印出网站中成功加载的所有资源。
通过 document.getElementsByTagName('img').length
减去上面的成功加载就能得出报错的图片资源数量了。
1 | // 返回网站内所有成功加载的png文件数量 |
5. Error事件捕获
资源加载错误,虽然会阻止冒泡,但是不会阻止捕获。true:捕获,false:冒泡
1 | // window.addEventListener第三个参数是true的时候是捕获的过程,false是冒泡的过程 |
6.延伸
为了提升web性能,大部分web产品都有CDN部署,将资源部署到不同的域名上,但是我们都知道浏览器是有同源策略的,当加载不同域名的脚本发生错误时,语法错误的细节不会报告,仅返回”Script error”
既然跨域JS运行错误可以捕获,错误提示是什么,应该怎么处理?

必须做俩件事:
- 客户端:在请求资源的
script
标签中增加crossorigin
属性 - 服务端:设置
js
资源响应头Access-Control-Origin:*
1 | <script type="text/javascript" src="http://domain.com/a.js" crossorigin></script> |
三. 上报错误的方式
开发 Web 应用程序过程中的一种常见的做法,就是集中保存错误日志,以便查找重要错误的原因。那么我们怎么将js的错误信息记录到服务器数据库库中呢。
- 采用Ajax通信的方式上报 (所有的错误监控都不是通过这种方式来做的;)
- 利用Image对象上报(所有的监控体系都是这样做的,如谷歌)
1. 采用Ajax通信的方式上报
ajax来实现的弊端
不支持跨域操作,因为很多情况下是一台服务器要负责处理多台服务器的错误;
大多数Ajax通信都是通过javascript库提供的包装函数来处理,如果库代码本身就有问题, 而你还在依赖该库记录信息,可想而知,错误消息是不肯能得到记录的。
怎么办?我们可以使用Image对象巧妙的解决这个问题
2.利用Image对象上报
Image对象的优点:
所有浏览器都支持 Image 对象,包括那些不支持
XMLHttpRequest
对象的浏览器。可以避免跨域限制。通常都是一台服务器要负责处理多台服务器的错误,而这种情况下使用
XMLHttpRequest
是不行的。在记录错误的过程中出问题的概率比较低。大多数 Ajax 通信都是由 JavaScript 库提供的包装函 数来处理的,如果库代码本身有问题,而你还在依赖该库记录错误,可想而知,错误消息是不 可能得到记录的。
1 | /* 方法1 */ |