在复杂的网络环境和浏览器环境下,自测、QA测试以及 Code Review 都是不够的,如果对页面稳定性和准确性要求较高,就必须有一套完善的代码异常监控体系,本文从前端代码异常监控的方法和问题着手,尽量全面地阐述错误日志收集各个阶段中可能遇到的阻碍和处理方案。
☞ 收集日志的方法
平时收集日志的手段,可以归类为两个方面,一个是逻辑中的错误判断,为主动判断;一个是利用语言给我们提供的捷径,暴力式获取错误信息,如 try..catch
和 window.onerror
。
1. 主动判断
我们在一些运算之后,得到一个期望的结果,然而结果不是我们想要的
1 2 3 4 5 6 7 8 9 10 11 |
// test.js function calc(){ // code... return val; } if(calc() !== "someVal"){ Reporter.send({ position: "test.js::<Function>calc" msg: "calc error" }); } |
这种属于逻辑错误/状态错误的反馈,在接口 status
判断中用的比较多。
2. try..catch
捕获
判断一个代码段中存在的错误:
1 2 3 4 5 6 |
try { init(); // code... } catch(e){ Reporter.send(format(e)); } |
以 init
为程序的入口,代码中所有同步执行出现的错误都会被捕获,这种方式也可以很好的避免程序刚跑起来就挂。
3. window.onerror
捕获全局错误:
1 2 3 4 5 |
window.onerror = function() { var errInfo = format(arguments); Reporter.send(errInfo); return true; }; |
在上面的函数中返回 return true
,错误便不会暴露到控制台中。下面是它的参数信息:
1 2 3 4 5 6 7 8 9 10 |
/** * @param {String} errorMessage 错误信息 * @param {String} scriptURI 出错的文件 * @param {Long} lineNumber 出错代码的行号 * @param {Long} columnNumber 出错代码的列号 * @param {Object} errorObj 错误的详细信息,Anything */ window.onerror = function(errorMessage, scriptURI, lineNumber,columnNumber,errorObj) { // code.. } |
window.onerror
算是一种特别暴力的容错手段,try..catch
也是如此,他们底层的实现就是利用 C/C++ 中的 goto
语句实现,一旦发现错误,不管目前的堆栈有多深,不管代码运行到了何处,直接跑到顶层或者 try..catch
捕获的那一层,这种一脚踢开错误的处理方式并不是很好。
☞ 收集日志存在的问题
收集日志的目的是为了及时发现问题,最好日志能够告诉我们,错误在哪里,更优秀的做法是,不仅告诉错误在哪里,还告诉我们,如何处理这个错误。终极目标是,发现错误,自动容错,这一步是最难的。
1. 无具体报错信息,Script error.
先看下面的例子,test.html
1 2 3 4 5 6 7 |
<!-- http://barret/test.html --> <script> window.onerror = function(){ console.log(arguments); }; </script> <script src="http://barret/test.js"></script> |
test.js
1 2 3 4 5 6 |
// http://barret/test.js function test(){ ver a = 1; return a+1; } test(); |
我们期望收集到的日志是下面这样具体的信息:
为了对资源进行更好的配置和管理,我们通常将静态资源放到异域上