这两天在看关于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。。。。问题总是一步步解决的。。
匿了~