近日騰訊音樂電話面試提到如何監控前端代碼報錯,涉及 js 代碼報錯,異步報錯,圖檔資源、js資源加載報錯,Promise報錯如何進行監控統計,答的不夠全面,于是仔細研究下。
- js 代碼報錯
- 異步報錯
- 圖檔請求報錯
- script src 資源加載報錯
- Promise reject 或者 抛錯
JS 異常處理
使用 try...catch...
try {
w
}catch(e){
console.log(e) // ReferenceError: w is not defined
}
異步處理
對于異步報錯,使用try catch是無法捕捉到錯誤的,因為異步事件已經放入事件隊列中,無法捕捉到。
于是可以采用在異步回調函數裡面進行 try catch,如果有若幹個異步事件都要進行 try catch就會比較繁瑣,後面會介紹。
try {
setTimeout(() => {
err
}, 10);
} catch (error) {
console.log(error); // 并不會列印
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yM2MTYldzM5kDNwkTZ1YWO5EGMiVmNzADZwIWOwMjY48CXyAzLcdDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL2M3Lc9CX6MHc0RHaiojIsJye.png)
圖檔請求
針對單個圖檔請求報錯可以調用 Image 對象提供的api onerror回調函數進行錯誤捕獲,那如果是很多圖檔呢?或者是其他的資源請求不到呢?
const img = new Image();
img.src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
img.onload = () => {
document.body.appendChild(img);
};
img.onerror = () => {
document.body.appendChild(new Text("Could not load the nebula :("));
};
Promise異常處理
通過 Promise 可以幫助我們解決異步回調地獄的問題,但是一旦 Promise 執行個體抛出異常而你沒有用 catch 去捕獲的話,onerror 或 try-catch 也無能為力,無法捕捉到錯誤,像如下示例報錯:
Promise.reject('promise error');
new Promise((resolve, reject) => {
reject('promise error');
});
new Promise((resolve) => {
resolve();
}).then(() => {
throw 'promise error'
});
可以使用 window.addEventListener
unhandledrejection
事件
MDN:
當
Promise
被 reject 且沒有 reject 處理器的時候,會觸發
unhandledrejection
事件
window.addEventListener("unhandledrejection", event => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
// Prevent the default handling (such as outputting the error to the console
event.preventDefault();
});
Promise.reject('promise error');
new Promise((resolve, reject) => {
reject('promise error');
});
new Promise((resolve) => {
resolve();
}).then(() => {
throw 'promise error'
});
全局異常捕獲 window.onerror
在MDN上是這麼介紹的
- 當JavaScript運作時錯誤(包括文法錯誤)發生時,
會觸發一個window
接口的ErrorEvent
事件,并執行error
。window.onerror()
- 當一項資源(如
或<img>
)加載失敗,加載資源的元素會觸發一個<script>
Event
事件,并執行該元素上的error
處理函數。這些error事件不會向上冒泡到window,不過(至少在Firefox中)能被單一的onerror()
捕獲。window.addEventListener
- 若該函數傳回
,則阻止執行預設事件處理函數(window.addEventListener('error', function(event) { ... }))。true
window.onerror = function (msg, url, lineNo, columnNo, error) {
var string = msg.toLowerCase();
var substring = "script error";
if (string.indexOf(substring) > -1){
alert('Script Error: See Browser Console for Detail');
} else {
var message = [
'Message: ' + msg,
'URL: ' + url,
'Line: ' + lineNo,
'Column: ' + columnNo,
'Error object: ' + JSON.stringify(error)
].join(' - ');
alert(message);
}
return false;
};
error
需要注意的是:
- window.onerror 事件必須寫在代碼運作之前,如果 寫在執行代碼之後,JS 代碼執行報錯了,就不會繼續捕獲到 window.onerror 事件了。
- window.onerror 是無法捕獲到網絡異常的錯誤
也可以通過 window.addEventListener('error') 進行捕獲錯誤。
如下示例請求圖檔資源失敗,由于網絡請求異常不會事件冒泡,是以必須在捕獲階段将其捕捉到才行,于是window.addEventListener 設定為 true 在捕獲階段進行
<img src="./1.png">
<img src="./2.png">
<img src="./3.png">
<img src="./4.png">
<script>
window.addEventListener('error', (event) => {
console.log(
event
);
}, true);
</script>
js 資源加載失敗也同圖檔一樣,錯誤事件監聽事件要提前。
<script>
window.addEventListener('error', (event) => {
console.log(
event
);
}, true);
</script>
<script src="12.js"></script>
特别的,如果 A 網站使用 B(CDN) 域名下的js資源,但是JS執行報錯了,浏覽器隻會給出 Script error 錯誤提示,不會有具體報錯資訊,原因是:浏覽器的同源政策限制。
為了能夠将CDN的報錯資訊顯示出來,可以做如下操作:
1、A網站的服務端配置:Access-Control-Allow-Origin: b.com
// http://a.com/index.html
<script>
window.onerror = function (error) {
console.log(error)
return true
};
</script>
<script src="http://b.com/test.js" crossorigin></script>