前端的異常收集常用的兩種方式:
<a >原文地址</a>
1.try catch
使用一個webpack的loader <a >babel_try_catch_loader</a>對js代碼進行包裹。
打包完成后,所有的函數塊會被加上try catch 我們只需在全局空間定義catch的函數,然后進行收集。
使用try catch 我們可以捕獲到
1.錯誤信息
2.文件名
3.函數塊行號
4.函數名稱
當然其他的一些信息我們可以在catch的錯誤函數中添加,例如時間,UA,項目名稱等。
但是try,catch的方案有2個缺點:
沒法捕捉try,catch塊,當前代碼塊有語法錯誤,JS解釋器壓根都不會執行當前這個代碼塊,所以也就沒辦法被catch住;
沒法捕捉到全局的錯誤事件,也即是只有try,catch的塊里邊運行出錯才會被你捕捉到,這里的塊你要理解成一個函數塊。
所以當我們使用try-catch方式來進行錯誤收集時,我們代碼最好使用函數式思想來編寫。
2.window.onerror
- 可以捕捉語法錯誤,也可以捕捉運行時錯誤;
- 可以拿到出錯的信息,堆棧,出錯的文件、行號、列號;
- 只要在當前頁面執行的js腳本出錯都會捕捉到,例如:瀏覽器插件的javascript、或者flash拋出的異常等。
- 跨域的資源需要特殊頭部支持。
<span style="color: red">需要注意的是:</span>
- window.onerror能捕捉到語法錯誤,但是語法出錯的代碼塊不能跟window.onerror在同一個塊
- 對于跨域的JS資源,window.onerror拿不到詳細的信息,需要往資源的請求添加額外的頭部。
window.onerror = (msg, url, line, col, error) => {
//沒有URL不上報!上報也不知道錯誤
if (msg != "Script error." && !url) {
return true;
}
setTimeout(() => {
var data = {};
//不一定所有瀏覽器都支持col參數
col = col || (window.event && window.event.errorCharacter) || 0;
data.url = url;
data.line = line;
data.col = col;
if (!!error && !!error.stack) {
//如果瀏覽器有堆棧信息
//直接使用
data.msg = error.stack.toString();
} else if (!!arguments.callee) {
//嘗試通過callee拿堆棧信息
var ext = [];
var f = arguments.callee.caller, c = 3;
//這里只拿三層堆棧信息
while (f && (--c > 0)) {
ext.push(f.toString());
if (f === f.caller) {
break;//如果有環
}
f = f.caller;
}
ext = ext.join(",");
data.msg = ext;
}
//把data上報到后臺!
//這里可以做日志上報
var img = new Image();
img.crossOrigin = 'Anonymous';
img.src = someURL + data;
}, 0);
return false;
};
window.onerror 看似完美,但當前這種環境下,框架都會自己攔截到err 然后再打印到控制臺,像angular。
在angular中需要寫一個注入方法替換默認錯誤處理方法:
.factory('$exceptionHandler', function() {
return function errHandle(e) {
//這里放window.onerror函數中的內容
};
})
本文只列方法,不做討論。另外關于錯誤的存儲和展示,那是又一塊大內容,暫不列舉~