首页 > 代码库 > js bug自动预警

js bug自动预警

这两天在看关于AMD中getCurrentScript函数时,突然想到,既然可以检测出当前出错的js文件,那么是不是可以做一个自动js bug预警的功能。以后只要有js错误出现,就会自动将错误上传到服务器。

先看司徒正美大大书中写的一段关于检测js文件地址的函数,相关博客地址点这:

function getCurrentScript(base) {
        // 参考 https://github.com/samyk/jiagra/blob/master/jiagra.js
        var stack;
        try {
            a.b.c(); //强制报错,以便捕获e.stack
        } catch (e) { //safari的错误对象只有line,sourceId,sourceURL
            stack = e.stack;
            if (!stack && window.opera) {
                //opera 9没有e.stack,但有e.Backtrace,但不能直接取得,需要对e对象转字符串进行抽取
                stack = (String(e).match(/of linked script \S+/g) || []).join(" ");
            }
        }
        if (stack) {
            /**e.stack最后一行在所有支持的浏览器大致如下:
             *chrome23:
             * at http://113.93.50.63/data.js:4:1
             *firefox17:
             *@http://113.93.50.63/query.js:4
             *opera12:http://www.oldapps.com/opera.php?system=Windows_XP
             *@http://113.93.50.63/data.js:4
             *IE10:
             *  at Global code (http://113.93.50.63/data.js:4:1)
             *  //firefox4+ 可以用document.currentScript
             */
            stack = stack.split(/[@ ]/g).pop(); //取得最后一行,最后一个空格或@之后的部分
            stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, ""); //去掉换行符
            return stack.replace(/(:\d+)?:\d+$/i, ""); //去掉行号与或许存在的出错字符起始位置
        }
        var nodes = (base ? document : head).getElementsByTagName("script"); //只在head标签中寻找
        for (var i = nodes.length, node; node = nodes[--i]; ) {
            if ((base || node.className === moduleClass) && node.readyState === "interactive") {
                return node.className = node.src;
            }
        }
    }

后面的node操纵是为了兼容IE,我们先不要管坑爹的IE,先来看看让我们心情愉悦的现代浏览器

在上面的函数,可以发现,e.stack简直是大杀器,基本只要分析里面的内容,就可以拿到具体错误位置

但是这段函数执行是有条件的,我们必须让其在加载进来的js文件环境下执行,这样才会报那个文件的错误嘛

为了模拟这个环境,我就顺手抄了个AMD,CMD中都用的函数define~

function define(callback){
    try{
        callback();
    }catch(e){
        var stack;
        stack = e.stack;
        if(!stack && window.opera){
            stack = (String(e).match(/of linked script \S+/g) || []).join(" ");
        }
        if(stack){
            stack = stack.split(/[@ ]/g).pop();
            stack = stack[0] === ‘(‘ ? stack.slice(1,-1):stack.replace(/\s/,"");
            stack = stack.replace(/(:\d+)?:\d*$/i,‘‘);
            bug_upload(stack);
            return;
        }
    }
}

里面的bug_upload是用来处理拿到的错误路径用的,这里为了方便,里面只是仅仅把路径alert出来。

然后我们把加载尽量的js用define包上,然后在测试代码里随便加了一个错误:

define(function(){
    function test_bug(){
        a.b.c();
    }

    test_bug();
});

准确弹出错误地址:

 

哇,好赞!那么下面我们就要搞定IE

IE新版本里面已经支持e.stack了,我们先干了IE旧版本!

考虑到IE发生错误时老弹出一个框,说你的页面有错误,很是让人愤怒!于是我觉得给他绑一个onerror事件:

window.onerror = function(msg,url){
    bug_upload(url);
    return true;
}

怎么把这段东西放到原来检测的大函数中呢,嘿嘿:

function define(callback){
    try{
        callback()
    }catch(e){
        var stack;
        stack = e.stack;
        if(!stack && window.opera){
            stack = (String(e).match(/of linked script \S+/g) || []).join(" ");
        }
        if(stack){
            stack = stack.split(/[@ ]/g).pop();
            stack = stack[0] === ‘(‘ ? stack.slice(1,-1):stack.replace(/\s/,"");
            stack = stack.replace(/(:\d+)?:\d*$/i,‘‘);
            bug_upload(stack);
            return;
        }
        window.onerror = function(msg,url){
            bug_upload(url);
            return true;
        }
        window.fireEvent && window.fireEvent(‘onerror‘,e);
    }
}
function bug_upload(path){
    alert(path);
}

搞定!!虽然这里IE老版本下只会弹出当前出错的html。。。。问题总是一步步解决的。。

匿了~