用戶
 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

掃一掃,登錄網站

小程序社區 首頁 教程 查看內容

湖人vs爵士:捕獲web與小程序JS異常的方法

湖人vs爵士季后赛 www.nbgeh.club Rolan 2019-11-26 00:50

前段時間,我們發現小程序異步代碼里的錯誤沒有上報到異常監控平臺,經過排查這部分小程序沒法直接監聽到,需要我們手動上報。再者,開發過程中,異常處理一直是不太受重視且容易遺漏的???。本文總結了JS異常的類型 ...

前段時間,我們發現湖人vs爵士季后赛異步代碼里的錯誤沒有上報到異常監控平臺,經過排查這部分小程序沒法直接監聽到,需要我們手動上報。再者,開發過程中,異常處理一直是不太受重視且容易遺漏的???。本文總結了JS異常的類型及捕獲方法,最后針對小程序給出錯誤處理經驗。


JS異常分類

  • Error:常規異常,一般為用戶自定義的異常,如 new Error("error message"),這類自定義的錯誤用來統計異常數據,直接上報即可;
  • RangeError:數值溢出越界異常,當 Number 類型變量超過指定的范圍,如
    var pi = 3.14159; pi.toFixed(100000);d(toFixed()方法參數只能接受 0~100) ;
  • ReferenceError:引用異常,當不存在的變量被使用的時候,這類錯誤一般在編碼檢查階段就會暴露;
  • SyntaxError:語法錯誤,作為解釋型語言的 JavaScript 只有到執行的時候才能識別出語法錯誤,這類錯誤在編碼檢查和構建階段就會暴露;
  • TypeError:類型錯誤,當調用不存在的對象方法或對象不存在時,例如:var foo = {}; foo.bar();為了避免這類錯誤出現,可使用防御式編程,但如若數據有誤則應拋出異常;
  • URIError:encodeURI() decodeURI() 方法參數不正確拋出的異常,例如:decodeURIComponent("%");
  • EvalError:eval() 方法參數不正確拋出的異常;


Web端對異常的捕獲能力

了解了異常的分類后,我們還需要知道瀏覽器如何捕獲到這些異常。

1)try-catch

JavaScript 里有 try-catch 語法塊,可用于異常捕獲處理。try-catch 可以成功捕獲大部分錯誤,但對于 SyntaxError 語法錯誤 和 異步代碼中的錯誤,則無法捕獲。

例如:SyntaxError 語法錯誤

try {
    var p = 
} catch(e) { 
    console.log('caught error: ', e.message)
}

// 輸出:Uncaught SyntaxError: Unexpected token '}'復制代碼

例如:異步代碼中的錯誤

try {
    setTimeout(function() {
        var p = error + 1
    }, 0)
} catch(e) {
    console.log('caught error:', e.message)
}

// 輸出:Uncaught ReferenceError: error is not defined復制代碼

2)error 事件

try-catch 針對我們預感到可能會有問題的代碼,捕獲異常進行處理,而對于一些我們未知的錯誤,可以使用 window 對象的 error 事件進行監聽。

error 事件可以捕獲到同步或異步(非 Promise )代碼中的非語法錯誤。

例如:異步代碼中的錯誤

window.addEventListener('error', e => {
  console.log('caught error', e.message);
  e.preventDefault();
});
setTimeout(function() {
    var p = error + 1
}, 0)

// 輸出:caught error Uncaught ReferenceError: error is not defined復制代碼

需要注意的是:e.preventDefault() 在 error 監聽事件中調用,可以阻止報告異常給瀏覽器,別讓瀏覽器默認地在控制臺輸出錯誤。

另外,文檔中也提到關于資源加載失敗的錯誤:

When a resource (such as an <img> or <script>) fails to load, an error event using interface Event is fired at the element that initiated the load, and the onerror() handler on the element is invoked. These error events do not bubble up to window, but (at least in Firefox) can be handled with a window.addEventListener configured with useCapture set to True.

對于圖片或腳本資源加載失敗,這類錯誤不會冒泡給 window,但可以在捕獲階段進行處理,即addEventListener 最后一個參數置為 true

window.addEventListener('error', e => {
    console.log('資源加載失敗');
}, true)復制代碼

3)unhandledRejection 與 rejectionhandled 事件

error 事件可以捕獲到非 Promise 的異步錯誤,而針對 Promise,window對象有專門的事件來處理這類錯誤。

當異步錯誤沒被 catch 住時,觸發 unhandledRejection 事件:

window.addEventListener('unhandledrejection', e => {
    console.log('caught unhandledrejection', e.reason);
    e.preventDefault();
})
var p = new Promise(function(resolve, reject) {
    tp = error + 1
})

// 輸出:caught unhandledrejection ReferenceError: error is not defined復制代碼

而當異步錯誤一開始未被 catch 住,過后才被 catch 的情況,會先觸發 unhandledRejection 事件,當被 catch 的時候,會觸發 rejectionhandled 事件:

window.addEventListener('unhandledrejection', e => {
    console.log('caught unhandledrejection', e.reason);
    e.preventDefault();
})
window.addEventListener('rejectionhandled', e => {
    console.log('caught rejectionhandled', e.reason);
    e.preventDefault();
})
var p = new Promise(function(resolve, reject) {
    tp = error + 1
})
setTimeout(() => {
    p.catch(e => console.log('catch', e.message))
}, 1000)

// 輸出:
// caught unhandledrejection ReferenceError: error is not defined
// (1s后)
// catch error is not defined
// caught rejectionhandled ReferenceError: error is not defined復制代碼

也就是說未處理的異常增加時會觸發 unhandledRejection,而未處理的異常(被處理后)減少時會觸發 rejectionhandled,這在上報異常中可以避免上報那些已經被處理過的異常。

關于兼容性,截止至本文成稿,移動端的支持程度還是可以的,iOS主流版本 和 Chrome 都支持:


(圖來源:unhandledrejection/rejectionhandled events,caniuse.com/#search=unh…


小程序端對異常的捕獲能力

小程序的 App 對象中有 onError 方法,相當于 web 端的 error 事件,可以捕獲到同步或異步(非 Promise )代碼中的非語法錯誤。而對于 Promise,小程序并沒有如 window 對象中的 unhandledRejection 與 rejectionhandled 事件,無法像 web 端那樣統一處理異常。

不過,既然都是 Promise 相關的錯誤,那么,我們可以改寫或覆蓋 Promise 對象,將其進行封裝把所有錯誤都 catch 住也就可以了。

推薦 promise-polyfill 這個輕量級的 promise 實現包,其中提供了 _unhandledRejectionFn 方法,用于捕獲那些未被處理的 Promise 異常。

import Promise from 'promise-polyfill';
Promise._unhandledRejectionFn = function(rejectError) {
    // 處理異?;蟶媳?/span>
}
復制代碼


總結

關于JS的異常總結已經差不多了,之前一直覺得這部分知識不夠系統,一來自己重視程度不夠,二來也是知識點不多但都較零散。經過這段時間收集資料,捋清思路,編碼實現還算有所收獲,便總結成文,若有不盡不祥不對之處煩請各位讀者多多指點。


參考文獻

  1. Exceptional Exception Handling in JavaScript
  2. 前端代碼異常監控實戰
  3. GlobalEventHandlers.onerror
  4. Promise rejection events in Using Promises
  5. promise-polyfill
分享至 : QQ空間
收藏
原作者: w_西城 來自: 掘金
七乐彩开奖走势图 广西快乐10分说明 20选5中奖率 北单上下单双怎么玩 dnf85在哪搬砖最赚钱 ca挖矿区块链赚钱 诺亚传说商人赚钱吗 半全场稳赚 多乐彩直选走势图 出来售楼还有什么工作赚钱 高恪赚钱 区块链工作室怎么赚钱 内蒙古时时彩11选5 AG水上乐园开奖视频 wow 采矿 赚钱 26选5三段式好彩