天天看點

前端異常監控

近日騰訊音樂電話面試提到如何監控前端代碼報錯,涉及 js 代碼報錯,異步報錯,圖檔資源、js資源加載報錯,Promise報錯如何進行監控統計,答的不夠全面,于是仔細研究下。

  1. js 代碼報錯
  2. 異步報錯
  3. 圖檔請求報錯
  4. script src 資源加載報錯
  5. 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); // 并不會列印
}           
前端異常監控

圖檔請求

針對單個圖檔請求報錯可以調用 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

    事件,并執行該元素上的

    onerror()

    處理函數。這些error事件不會向上冒泡到window,不過(至少在Firefox中)能被單一的

    window.addEventListener

    捕獲。
  • 若該函數傳回

    true

    ,則阻止執行預設事件處理函數(window.addEventListener('error', function(event) { ... }))。
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           
前端異常監控

需要注意的是:

  1. window.onerror 事件必須寫在代碼運作之前,如果 寫在執行代碼之後,JS 代碼執行報錯了,就不會繼續捕獲到 window.onerror 事件了。
  2. 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>