JS异常处理与应用

一、简介
作为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 defined
  • url:出错脚本所在的url
  • lineNumber:出错脚本的行数

若使用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);
        }
    };

六、附录

1、兼容多数浏览器的实现库

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)
-

Fork me on GitHub