日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747


JavaScript異常錯誤處理指南

 

 

在前端的 JAVAScript 開發(fā)中,發(fā)現(xiàn)開發(fā)者對于錯誤異常的處理普遍都比較簡單粗暴,如果應(yīng)用程序中缺少有效的錯誤處理和容錯機(jī)制,代碼的健壯性就無從談起。本文整理出了一些常見的錯誤異常處理的場景,旨在為前端的 JavaScript 錯誤異常處理提供一些基礎(chǔ)的指導(dǎo)。

 

Error 對象

先來簡單介紹一下 JavaScript 中的 Error 對象,通常 Error 對象由重要的兩部分組成,包含了 error.message 錯誤信息和 error.stack 錯誤追溯棧。

產(chǎn)生一個錯誤很簡單,比如在 foo.js 中直接調(diào)用一個不存在的 callback 函數(shù)。

// foo.jsfunction foo () {    callback();}foo();

此時通過 Chrome 瀏覽器的控制臺會展示如下的信息。

Uncaught ReferenceError: callback is not defined    at foo (foo.js:2)    at foo.js:5

其中 Uncaught ReferenceError: callback is not defined 就是 error.message 錯誤信息,而剩下的 at xxx 就是具體的錯誤追溯棧,在 Chrome 的控制臺中,對錯誤的展示進(jìn)行了優(yōu)化。

如果我們通過 window.onerror 來捕獲到該錯誤后將 Error 對象直接輸出到頁面中會展示出更原始的數(shù)據(jù)。

<!-- 展示錯誤的容器 --><textarea id="error"></textarea>// 輸出錯誤window.onerror = function (msg, url, line, col, err) {    document.getElementById('error').textContent = err.message + 'nn' + err.stack;};

原始的錯誤數(shù)據(jù)中會展示出錯誤追溯棧中的 Source URL。

callback is not definedReferenceError: callback is not defined    at foo (http://example.com/js-error/foo.js:2:5)    at http://example.com/js-error/foo.js:5:1

有了錯誤追溯棧,就能通過發(fā)生錯誤的文件 Source URL 和錯誤在代碼中的具體位置來快速定位到錯誤。

看起來好像很簡單,但實(shí)際的開發(fā)中如何有效的捕獲錯誤,如何有效的拋出錯誤都有一些需要注意的點(diǎn),下面逐個的來講解。

 

window.onerror

前端在捕獲錯誤時都會通過綁定 window.onerror 事件來捕獲全局的 JavaScript 執(zhí)行錯誤,標(biāo)準(zhǔn)的瀏覽器在響應(yīng)該事件時會依次提供 5 個參數(shù)。

window.onerror = function(message, source, lineno, colno, error) { ... }
  1. message 錯誤信息
  2. source 錯誤發(fā)生時的頁面 URL
  3. lineno 錯誤發(fā)生時的 JS 文件行數(shù)
  4. colno 錯誤發(fā)生時的 JS 文件列數(shù)
  5. error 錯誤發(fā)生時拋出的標(biāo)準(zhǔn) Error 對象

使用 window.addEventListener 也能綁定 error 事件,但是該事件函數(shù)的參數(shù)是一個 ErrorEvent 對象。

綁定 window.onerror 事件時,事件處理函數(shù)的第 5 個參數(shù)在低版本瀏覽中或 JS 資源跨域場景下可能不是 Error 對象。

 

在 Chrome 瀏覽器中如果頁面加載的 JS 資源文件中存在跨域的 script 標(biāo)簽,在發(fā)生錯誤時會提示 Script error 而缺乏錯誤追溯棧。

window.onerror 在響應(yīng)跨域 JavaScript 錯誤時缺乏錯誤追溯棧時的 arguments 對象如下:

[    'Script error.',    '',    0,    0,    null]

為了正常的捕獲到跨域 JS 資源文件的錯誤,需要具備兩個條件: 1. 為 JS 資源文件增加 CORS 響應(yīng)頭。 2. 通過 script 引用該 JS 文件時增加 crossorigin="anonymous" 的屬性,如果是動態(tài)加載的 JS,可以寫作 script.crossOrigin = true 。

window.onerror 能捕獲一些全局的 JavaScript 錯誤,但還有不少場景在全局是捕獲不到的。

 

try/catch

window.onerror 能捕獲全局場景下的錯誤,如果已知一些程序的場景中可能會出現(xiàn)錯誤,這個時候一般會使用 try/catch 來進(jìn)行捕獲。

但是在使用 try/catch 塊時無法捕獲異步錯誤,例如塊中使用了 setTimeout 。

try {    setTimeout(function () {        callTimeout();  // callTimeout 未定義,會拋錯    }, 1000);}catch (err) {    console.log('catch the error', err); // 不會被執(zhí)行}

try/catch 在處理 setTimeout 這類異步場景時是無效的,執(zhí)行時仍會拋錯,catch 中的代碼不會被執(zhí)行。

雖然在 try/catch 中沒有捕獲到,此時如果有綁定 window.onerror 則會被全局捕獲。

由此可見, try/catch 應(yīng)該是只能捕獲 JS Event Loop 中同步的任務(wù)。

如果想正確的捕獲 setTimeout 中的錯誤,需要將 try/catch 塊寫到 setTimeout 的函數(shù)中。

setTimeout(function () {    try {        callTimeout(); // callTimeout 未定義,不會拋錯    }    catch (err) {        console.log('catch the error', err); // 將會被執(zhí)行    }}, 1000);

Promise

Promise 有自己的錯誤處理機(jī)制,通常 Promise 函數(shù)中的錯誤無法被全局捕獲。

var promise = new Promise(executor);promise.then(onFulfilled, onRejected);

比較容易遺漏錯誤處理的地方有 executor 和 onFulfilled ,在這些函數(shù)中如果發(fā)生錯誤都不能被全局捕獲。

正確的捕獲 Promise 的錯誤,應(yīng)該使用 Promise.prototype.catch 方法,意外的錯誤和使用 reject 主動捕獲的錯誤都會觸發(fā) catch 方法。

 

catch 方法中通常會接收到一個 Error 對象,但是當(dāng)調(diào)用 reject 函數(shù)時傳入的是一個非 Error 對象時,catch 方法也會接收到一個非 Error 對象,這里的 reject 和 throw 的表現(xiàn)是一樣的,所以在使用 reject 時,最好是傳入一個 Error 對象。

reject(    new Error('this is reject message'));

值得注意的是,如果 Promise 的 executor 中存在 setTimeout 語句時, setTimeout 的報錯會被全局捕獲。

 

Async Function

Async Function 和 Promise 一樣,發(fā)生錯誤不會被全局的 window.onerror 捕獲,所以在使用時如果有報錯,需要手動增加 try/catch 語句。

匿名函數(shù)

匿名函數(shù)的使用在 JavaScript 中很常見,但是當(dāng)出現(xiàn)匿名函數(shù)的報錯時,在錯誤追溯棧中會以 anonymous 來標(biāo)識錯誤,為了排查錯誤方便,可以將函數(shù)進(jìn)行命名,或者使用函數(shù)的 displayName 屬性。

函數(shù)如果有 displayName 屬性,在錯誤棧中會展示該屬性值,如果用于命名重要的業(yè)務(wù)邏輯屬性,將有效幫助排查錯誤。

 

throw error

上面說了很多錯誤捕獲的注意點(diǎn),如果要主動的拋錯,都會使用 throw 來拋錯,常見的幾種拋錯方法如下:

throw new Error('Problem description.')  // 方法 1throw Error('Problem description.')      // 方法 2throw 'Problem description.'             // 方法 3throw null                               // 方法 4

其中方法 1 和方法 2 的效果一樣,瀏覽器都能正確的展示錯誤追溯棧。方法 3 和方法 4 不推薦,雖然能拋錯,但是在拋錯的時候不能展示錯誤追溯棧。

try/catch 和 throw ,一個用來捕獲錯誤,一個用來拋出錯誤,如果兩個結(jié)合起來用通常等于脫了褲子放屁多此一舉,唯一有點(diǎn)用的是可以對錯誤信息進(jìn)行再加工。

可以在 Chrome 控制臺中模擬出一個結(jié)合使用的實(shí)際場景。

try {    foo();}catch (err) {    err.message = 'Catch the error: ' + err.message;    throw Error(err);}

由于在 catch 塊中又拋出了錯誤,所以該錯誤沒有被捕獲到,但此時錯誤信息經(jīng)過了二次封裝。

Uncaught Error: ReferenceError: Catch the error: foo is not defined

通過對錯誤信息的二次封裝,可以增加一些有利于快速定位錯誤的額外信息。

 

原作者:雨夜帶刀's Blog

分享到:
標(biāo)簽:JavaScript
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定