2019-04-18-09:53:于公司
需要處理哪些異常址芯?
對于前端來說要销,我們可做的異常捕獲還真不少〖涡埽總結(jié)一下遥赚,大概如下:
- JS 語法錯誤、代碼異常
- AJAX 請求異常
- 靜態(tài)資源加載異常
- Promise 異常
- Iframe 異常
- 跨域 Script error
- 崩潰和卡頓
window.onerror
當(dāng) JS 運行時錯誤發(fā)生時记舆,window 會觸發(fā)一個 ErrorEvent 接口的 error 事件,并執(zhí)行 window.onerror()呼巴。
window.onerror = function(message, source, lineno, colno, error){
console.log("捕獲到異常:", {message, source, lineno, colno, error});
}
可以在瀏覽器嘗試下:
window.onerror = function(message, source, lineno, colno, error){
console.log("捕獲到異常:", {message, source, lineno, colno, error});
};
setTimeout(()=>{
ton;
})
onerror 不是萬能的
window.onerror = function(message, source, lineno, colno, error){
console.log("捕獲到異常:", {message, source, lineno, colno, error});
};
<img src="./jar.png" />
需要注意:
- onerror 最好寫在所有 JS 腳本的前面泽腮,否則有可能捕獲不到錯誤;
- onerror 無法捕獲語法錯誤衣赶;
Promise Catch
在 promise 中使用 catch 可以非常方便的捕獲到異步 error 诊赊,這個很簡單。沒有寫 catch 的 Promise 中拋出的錯誤無法被 onerror 或 try-catch 捕獲到府瞄,所以我們務(wù)必要在 Promise 中不要忘記寫 catch 處理拋出的異常碧磅。
解決方案:為了防止有漏掉的 Promise
異常,建議在全局增加一個對 unhandledrejection
的監(jiān)聽遵馆,用來全局監(jiān)聽Uncaught Promise Error
鲸郊。使用方式:
window.addEventListener("unhandledrejection", function(e){
console.log(e);
})
嘗試:
window.addEventListener("unhandledrejection", function(e){
e.preventDefault();
console.log(e);
return true;
});
new Promise((resolve, reject)=>{
reject("jar: promise error");
})
這樣,無論promise是否去catch货邓,都會捕獲秆撮。
iframe 異常
對于 iframe 的異常捕獲,我們還得借力 window.onerror:
<iframe src="./iframe.html" />
window.frames[0].onerror = function(message, source, lineno, colno, error){
console.log("iframe捕獲:", {message, source, lineno, colno, error});
return true;
}
script error
一般情況换况,如果出現(xiàn) Script error 這樣的錯誤职辨,基本上可以確定是出現(xiàn)了跨域問題盗蟆。這時候,是不會有其他太多輔助信息的舒裤,但是解決思路無非如下:
跨源資源共享機(jī)制( CORS ):我們?yōu)?script 標(biāo)簽添加 crossOrigin 屬性喳资。
<script src="http://sss.com/main.js" crossorigin></script>
** 特別注意,服務(wù)器端需要設(shè)置:Access-Control-Allow-Origin **
崩潰和卡頓
卡頓也就是網(wǎng)頁暫時響應(yīng)比較慢腾供, JS 可能無法及時執(zhí)行仆邓。但崩潰就不一樣了,網(wǎng)頁都崩潰了台腥,JS 都不運行了宏赘,還有什么辦法可以監(jiān)控網(wǎng)頁的崩潰,并將網(wǎng)頁崩潰上報呢黎侈?
崩潰和卡頓也是不可忽視的察署,也許會導(dǎo)致你的用戶流失。
利用 window 對象的 load
和 beforeunload
事件實現(xiàn)了網(wǎng)頁崩潰的監(jiān)控峻汉。
基于以下原因贴汪,我們可以使用
Service Worker
來實現(xiàn)網(wǎng)頁崩潰的監(jiān)控:
Service Worker
有自己獨立的工作線程,與網(wǎng)頁區(qū)分開休吠,網(wǎng)頁崩潰了扳埂,Service Worker
一般情況下不會崩潰;
Service Worker
生命周期一般要比網(wǎng)頁還要長瘤礁,可以用來監(jiān)控網(wǎng)頁的狀態(tài)阳懂;
網(wǎng)頁可以通過 navigator.serviceWorker.controller.postMessage API
向掌管自己的 SW 發(fā)送消息。
React 異常捕獲
React 16 提供了一個內(nèi)置函數(shù) componentDidCatch
柜思,使用它可以非常簡單的獲取到 react 下的錯誤信息岩调。
UI 的某部分引起的 JS 錯誤不應(yīng)該破壞整個程序,為了幫 React 的使用者解決這個問題赡盘,React 16 介紹了一種關(guān)于錯誤邊界(error boundary)的新觀念号枕。
錯誤上報
1、通過Ajax發(fā)送數(shù)據(jù):
因為 Ajax 請求本身也有可能會發(fā)生異常陨享,而且有可能會引發(fā)跨域問題葱淳,一般情況下更推薦使用動態(tài)創(chuàng)建 img 標(biāo)簽的形式進(jìn)行上報。
2抛姑、動態(tài)創(chuàng)建 img 標(biāo)簽的形式:
function(error){
let reportUrl = "http://xxx.com/report";
new Image.src = `${reportUrl}?logs=${error}`;
}
收集異常信息量太多赞厕,怎么辦?實際中定硝,我們不得不考慮這樣一種情況:如果你的網(wǎng)站訪問量很大坑傅,那么一個必然的錯誤發(fā)送的信息就有很多條,這時候喷斋,我們需要設(shè)置采集率唁毒,從而減緩服務(wù)器的壓力:
Reporter.send = function(data){
// 只采集 30%
if(Math.random() < 0.3){
send(data); // 上報
}
}
采集率應(yīng)該通過實際情況來設(shè)定蒜茴,隨機(jī)數(shù),或者某些用戶特征都是不錯的選擇浆西。