• JavaScript代码异常监控


     JavaScript代码异常监控

    JavaScript异常一般有两方面:语法错误和运行时错误。两种错误的捕获和处理方式不同,从而影响具体的方案选型。通常来说,处理JS异常的方案有两种:

    try...catch 运行时非异步

    window.onerror 运行时错误(包括语法错误)

    document.onerror 资源加载异常(不会向上冒泡到window,不过能被单一的window.addEventListener捕获)

    window.addEventListener(‘error’) 资源加载异常,语法错误

    window.addEventListener(“unhandledrejection”) 获取promise对象没有rejection处理器时异常情况

    Promise.then().catch(cb)

    a、全局捕获

    通过全局的接口,将捕获代码集中写在一个地方,可以利用的接口有:

    • window.addEventListener(‘error’) / window.addEventListener(“unhandledrejection”) / document.addEventListener(‘click’) 等
    • 框架级别的全局监听,例如aixos中使用interceptor进行拦截,vue、react都有自己的错误采集接口
    • 通过对全局函数进行封装包裹,实现在在调用该函数时自动捕获异常,例如封装ajax请求等
    • 对实例方法重写(Patch),在原有功能基础上包裹一层,例如对console.error进行重写,在使用方法不变的情况下也可以异常捕获

    b、单点捕获

    在业务代码中对单个代码块进行包裹,或在逻辑流程中打点,实现有针对性的异常捕获:

    • try…catch
    • 专门写一个函数来收集异常信息,在异常发生时,调用该函数
    • 专门写一个函数来包裹其他函数,得到一个新函数,该新函数运行结果和原函数一模一样,只是在发生异常时可以捕获异常

    1、try...catch捕获

    这种方案要求开发人员在编写代码的时候,在预估有异常发生的代码段使用try...catch,在发生异常时将异常信息发送给接口:

    但是 try-catch 处理异常的能力有限,只能捕获捉到运行时非异步错误,对于语法错误异步错误就显得无能为力,捕捉不到。

    try{
    //可能发生异常的代码段
    }catch(e){
    //将异常信息发送服务端
    }

    try...catch的优点是可以细化到每个代码块,并且可以自定义错误信息以便统计。

    具体到上文提到的两种js异常,try...catch无法捕获语法错误,当遇到语法错误时,浏览器仍然会抛出错误Uncaught SyntaxError,但是不会被捕获,不会走进catch的代码块内。

    另外,如果try代码块中有回调函数也不会被捕获,比如:

    try{
    var btn = $('#btn');
        btn.on('click',function(){
            //throw error
        });
    }catch(e){}

    上述代码中btn的监听函数里抛出的异常无法被外层的catch捕获到,必须额外套一层:

    try{
    var btn = $('#btn');
        btn.on('click',function(){
            try{
                //throw error
            }catch(e){}
        });
    }catch(e){}

    综上所述,try...catch方案的部署非常复杂,如果人工部署除了要求巨量的工作量,还跟开发人员的能力和经验有关。如果依赖编译工具部署(比如fis),那每个代码块都套一层try...catch也是非常难看的并且容易引发一些不可预估的问题。

     window.onerror捕获

    window.onerror 捕获异常能力比 try-catch 稍微强点,无论是异步还是非异步错误,onerror 都能捕获到运行时错误。

    这种方式不需要开发人员在代码中书写大量的try...catch,通过给window添加onerror监听,在js发生异常的时候便可以捕获到错误信息,语法异常和运行异常均可被捕获到。但是window.onerror这个监听必须放在所有js文件之前才可以保证能够捕获到所有的异常信息。

    window.onerror 函数只有在返回 true 的时候,异常才不会向上抛出,否则即使是知道异常的发生控制台还是会显示 Uncaught Error: xxxxx。

    对于 onerror 这种全局捕获,最好写在所有 JS 脚本的前面,因为你无法保证你写的代码是否出错,如果写在后面,一旦发生错误的话是不会被 onerror 捕获到的。

    外 onerror 是无法捕获到网络异常的错误。

    window.onerror事件的详细信息参考这里

    /**
     * @param {String}  errorMessage   错误信息
     * @param {String}  scriptURL      出错文件的URL
     * @param {Long}    lineNumber     出错代码的行号
     * @param {Long}    columnNumber   出错代码的列号
     * @param {Object}  errorObj       错误信息Object
     */
    window.onerror = function(errorMessage, scriptURL, lineNumber,columnNumber,errorObj) { 
        // code..
    }

    onerror的实现方式各浏览器略有差异,但是前三个参数都是相同的,某些低版本浏览器没有后两个参数。

    最后一个参数errorObj各浏览器实现的程度不一致,具体可参考这里

    下图是被onerror捕获到的一个异常的具体信息:

    综上所述,window.onerror方案的优点是减少了开发人员的工作量,部署方便,并且可以捕获语法错误和运行错误。缺点是错误信息不能自定义,并且errorObj每种浏览器的实现有略微差异,导致需统计的信息有局限性。

    由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,但是这种方式虽然可以捕捉到网络请求的异常,但是无法判断 HTTP 的状态是 404 还是其他比如 500 等等,所以还需要配合服务端日志才进行排查分析才可以。

     跨域JS文件异常的捕获

    为了提高web性能,目前大部分web产品架构中都有CDN这一环,将资源部署到不同的域名上,充分利用浏览器的并发请求机制。那么在跨域JS文件中发生异常的时候,onerror监听会捕获到什么信息呢?请看下图:

    只有一个稍微有价值的信息Script error,其他什么信息都没有,为什么会这样呢?

    我们都知道浏览器有同源资源限制,常规状态下是无法进行跨域请求的。而script、img、iframe标签的src属性是没有这种限制的,这也是很多跨域方案的基础。但是即使script标签可以请求到异域的js文件,此文件中的信息也并不能暴露到当前域内,这也是浏览器的安全措施所致。

    那么有没有办法获取到异域资源的异常信息呢?

    其实很简单,目前可以说基本上所有的web产品对于js/css/image等静态资源都在服务端设置了Access-Control-Allow-Origin: *的响应头,也就是允许跨域请求。在这个环境下,只要我们在请求跨域资源的script标签上添加一个crossorigin属性即可:

    <script src="http://static.toutiao.com/test.js" crossorigin></script>

    这样的话,异域的test.js文件中发生异常时便可以被当前域的onerror监听捕获到详细的异常信息。

    参考网页:
    1、前端性能与异常上报

  • 相关阅读:
    ccache——/root/.ccache
    Ionic 2 | Tutorial | Let’s Create Our First Application
    Ionic 2 Tutorial
    搭建移动端框架Ionic+Genymotion开发环境
    【2020】输出矩阵
    【2015】给一个不多于三位的正整数,求出它是几位数,并分别打印出各位上的数字。
    【2021】小球走过的路程
    【2022】余料最少
    【2023】将十进制数转化为二进制数
    【2024】求X到Y之间的整数和
  • 原文地址:https://www.cnblogs.com/fqlGlog/p/9138227.html
Copyright © 2020-2023  润新知