一、简介
作为Web开发者,经常要跟JS打交道,可能由于网络超时、浏览器兼容性问题、缓存等原因,造成浏览器执行页面JS脚本时,会抛出异常。对Web开发者来说,JS异常很常见,但对于用户来说,JS异常却很陌生。因此如果能收集异常,提供统一的异常处理方式和友好的异常提示方式,将能大大提供用户体验。此外,如果能够及时的跟踪和统计页面的JS异常,对于开发者来说是一个福音,不仅能够快速地对异常进行响应还能对异常进行归档分析。
二、常见的JS异常
- EvalError
- RangeError
- ReferenceError
- SyntaxError
- TypeError
- URIError
三、JS异常捕获
捕获浏览器中的JS运行时错误,主要通过监听window.onerror事件和try/catch来实现。
1、window.onerror : 对于不同的脚本执行方式以及不同的浏览器,捕获到的信息会有区别
window.onerror 接收3个参数:
msg
:错误描述,比如:a is not definedurl
:出错脚本所在的urllineNumber
:出错脚本的行数
若使用window.addEventListener(‘error’,callback,false),callback的第一个参数并不是event对象而是Error对象。因此使用window.onerror是一个不错的选择,但使用.操作符进行事件监听是可以重载的,并且包含异常处理的脚本理论上要放在所有JS之前。
2、try/catch : 可通过e.stack打印异常信息
try{
fn()
}catch(e){
alert(e.stack);
}
本文将对不同浏览器和不同的脚本执行方式进行测试,并总结这些区别。
首先对于脚本的执行主要有以下几种方式:
- 页面内嵌的
<script>
,需要执行的代码在<script>
标签内 - 使用
<script src="external.js">
的方式引入外部脚本,脚本为同域地址 - 使用
<script src="external.js">
的方式引入外部脚本,脚本为不同域地址 - 使用
<script src="external.js">
的方式引入外部脚本,脚本为本地地址 - 使用eval方法来执行脚本
- 动态地创建内嵌的
<script>
并设置其innerHTML为需要执行的代码
四、异常的利用
1、线上实际运行时,若出现JS错误,JS报错信息自动已邮件的方式发送至前端开发团队,团队成员每个人自己认领、解决问题。这种方式解决了最基本的问题,错误的及时跟踪和响应。不过也存在一个问题,如何避免同样的错误。
解决思路如下:
- 以URL为单元,记录同一个页面的错误,方便统一解决
- 记录错误信息: PageURL、User Agent、Script URL、Error Message和Line Number
- 每个错误解决后,统一对错误进行统计和归档,形成知识库
2、注意点
- 收集数据的时候使用POST方式: 有时候ErrorMessage可能会比较长,浏览器URL长度是有限制的,若错误信息不多的情况,可以使用GET发送,但通常来说POST可以把所有数据都发送到后台
- 何时发送数据: 建议在触发onerror的时候发送
- 数据入库以哪个作为索引比较好: 通常来说使用URL可能会比较适合多数网站,也可以使用Error作为索引,具体根据实际场景进行选择
五、简单示例
window.onerror = function(msg,url,lineNumber){
var msgText = ['####异常行为号: '+lineNumber,
'异常信息为: '+msg,'异常发生的地址为: '+url].join('\n');
if (window.console && window.console.log){
window.console.log(msgText);
}else{
alert(msgText);
}
};
六、附录
2、以下是各浏览器执行各类脚本的异常捕获情况
Chrome (23.0.1271.101)
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script | |
msg | ✓ |
✓ |
✗(only Script error) |
✗(only Script error) |
✓ |
✓ |
url | ✓(current page) |
✓ |
✗(””) |
✗(””) |
✓(current page) |
✓(current page) |
lineNumber | ✓(from current page) |
✓ |
✗(0) |
✗(0) |
✓(from code) |
✓(from its code) |
Firefox (16.0.2)
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script | |
msg | ✓ |
✓ |
✗(only Script error) |
✗(only Script error) |
✓ |
✓ |
url | ✓(current page) |
✓ |
✓ |
✓ |
✓(file that call this eval) |
✓(current page) |
lineNumber | ✓(from current page)) |
✓ |
✗(0) |
✗(0) |
✓(position that calls this eval) |
✓(from its code) |
Safari (6.0.2 (8536.26.17))
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script | |
msg | ✓ |
✓ |
✗(only Script error) |
✓ |
✓ |
✓ |
url | ✓(current page) |
✓ |
✓ |
✓ |
✗(undefined) |
✓(current page) |
lineNumber | ✓(from current page) |
✓ |
✗(0) |
✓ |
✓(from code) |
✓(from its code) |
Opera (12.11)
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script | |
msg | ✓ |
✓ |
✗(only Script error) |
- | ✓ |
✓ |
url | ✓(current page) |
✓ |
✗(””) |
- | ✗(””) |
✓(current page) |
lineNumber | ✓(from current page) |
✓ |
✗(0) |
- | ✓(from code) |
✓(from its code) |
IE9
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script | |
msg | ✓ |
✓ |
✓ |
✓ |
✓ |
✓ |
url | ✓(current page) |
✓ |
✓ |
✓ |
✓(file path that call this eval) |
✓(current page) |
lineNumber | ✓(from current page) |
✓ |
✓ |
✓ |
✓(position that calls this eval) |
✓(from its code) |
IE8
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script(not available) | |
msg | ✓ |
✓ |
✓ |
✓ |
✓ |
- |
url | ✓(current page) |
✓ |
✓ |
✓ |
✓(file path that call this eval) |
- |
lineNumber | ✓(from current page) |
✓ |
✓ |
✓ |
✓(position that calls this eval) |
- |
IE7
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script(not available) | |
msg | ✓ |
✓ |
✓ |
✓ |
✓ |
- |
url | ✓(current page) |
✓ |
✓ |
✓ |
✓(file path that call this eval) |
- |
lineNumber | ✓(from current page) |
✓ |
✓ |
✓ |
✓(position that calls this eval) |
- |
IE6
page script | external script ( same origin ) | external script ( cross domain ) | external script ( local ) | eval | dynamic page script(not available) | |
msg | ✓ |
✓ |
✓ |
✓ |
✓ |
- |
url | ✓(current page) |
✓(current page) |
✓(current page) |
✓(current page) |
✓(current page) |
- |
lineNumber | ✓(from current page) |
✓(line number start from 1) |
✓(line number start from 1) |
✓(line number start from 1) |
✓(position that calls this eval,line number start from 1) |
- |