做有态度的前端团队

网易FEG前端团队

关于小组页面脚本错误捕获

平时本地或者测试环境开发,我们都能在调试面板之类的很直观看到脚本错误,出什么错,在哪,错误定位,一目了然,还能断点调试,这部分错误,一般会在开发以及QA测试阶段,就能大部分发现与修复。但是,如何捕获发现线上用户的错误呢?用户的网络、浏览器、电脑、手机等千奇百怪,总不能每次都远程用户电脑看一下它的Chrome吧?

一、如何捕获错误?

1、全局方式

window.onerror函数,可以捕获追踪全局的脚本错误,只要报错了,就会调用此函数,函数具体使用参数如下:

    window.onerror = function(msg,url,line,col,errorObj){
        
        console.log(msg); //错误的具体信息,字符串来,提示错误的具体内容(并没有错误堆栈)
        console.log(url); //错误的脚本文件地址,字符串,提示发生错误的具体文件
        console.log(line); //错误的行数
        console.log(col); //错误的列数,注意低版本IE是没有此参数
        console.log(errorObj); //错误信息的对象,保存着错误的堆栈和详情,低版本IE也没有此参数
    }

从上面参数来看,几乎能满足我们的需要了,只要统一每个页面都引用这段代码,就能监控用户的错误了,那实际用起来的时候,会有什么问题和限制呢?是不是真那么好用?

  • 基于安全考虑,webkit内核的,只会显示同源的脚本错误信息,外域的,统一提示Script Error,然后第0行错误,当然这个是有办法解决,给script添加属性crossorigin,以及服务器需要返回头部Access-Control-Allow-Origin:*,这样就能显示完整的错误信息了

  • 测试发现,会上报很多莫名其妙的错误上来,而对应的错误文件地址,跟我们完全没有关系。window.onerror会捕获页面所有的错误,包括浏览器第三方插件页面被劫持塞进去的脚本浏览器本身错误等等,然而这些我们是没法修复。

  • 大部分情况下,我们只能获取到错误的信息和行数,没有堆栈信息,比如:a is Undefined,错误文件是:jquery.js,行数是第1行;懵圈了,我想应该不是jquery的问题,是我们代码调用了jquery方法,但出错了,结果,这个错误上报了,等于没上报,也不知道哪有问题。

基于上面考虑,这种方式一般不采用(一开始是使用,后来放弃了)。

2、局部方式

try-catch模式,可以捕获包裹在try内的函数错误,报错了,就会调用catch回调:

    try{
        //do something
    }
    catch(e){
        console.log(e); //错误信息对象,包含堆栈信息
    }

try-catch对比起window.onerror,兼容性更强,而且不存在同源跨域问题,错误捕获的信息更加全,定位错误会更加容易些,也不会上报一些乱七八糟的内容,不过使用有一些局限性:

  • 需要针对每个需要的地方用try-catch包裹起来,写多了,就烦,改起来也头疼
  • 异步回调和事件代理,是捕获不了错误,例如下面这种:
    try{
        setTimeout(function(){
            //do something
        },1000);
    }
    catch(e){}

即使setTimeout中代码出错了,依然catch不到错误

    try{
        $("#btn").on("click",function(){
            //do something
        });
    }
    catch(e){}

跟上面一样,点击了按钮,出错了,也捕获不到,除非你的try-catch是包裹do something回调函数内,所以不能直接用一个try-catch包裹住整个js文件代码

二、选择与改进

基于同源以及错误信息的精确详细等情况,最终选择了try-catch方式来做错误捕获

1、将try-catch集成到AMD或者CMD的模块中

    nie.define = function(name,cb){
        try{
            cb();
        }
        catch(e){}
    }

比如上面这样,在定义模块的函数中插入,这样写代码时候,就不用去刻意写try-catch了,但需要推进大家使用模块化开发,也有利于大家的模块化思维。

2、重写常用回调与代理函数

异步回调,以及代理事件,即使用了上面的方式,也依然捕获不了错误,所以,唯一办法就重写他们,然后捕获回调

  • 重写了JS原生的函数,比如:setTimeoutsetIntervaladdEventListener等方法
  • 重写了组内常用的jQuery库的函数,比如:$.bind$.on$.ajax

这样能满足大部分的场景需求了

3、错误上报

使用开源的错误统计系统,来做统计查询与邮件发送等事情

三、后记

错误统计,能主动发现线上用户的错误,以及项目上线后的一些情况,错误系统会后续开放给大家,目前还存在一些小问题。

手机阅读请扫描下方二维码:

none
上一篇:Augmented Reality   下一篇:CORS跨域资源共享

添加新评论

ali-40.gifali-41.gifali-42.gifali-43.gifali-44.gifali-45.gifali-46.gifali-47.gifali-48.gifali-49.gifali-50.gifali-51.gifali-52.gifali-53.gifali-54.gifali-55.gifali-56.gifali-57.gifali-58.gifali-59.gifali-60.gifali-61.gif