亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

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

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


JavaScript異常錯(cuò)誤處理指南

 

 

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

 

Error 對象

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

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

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

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

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

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

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

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

原始的錯(cuò)誤數(shù)據(jù)中會展示出錯(cuò)誤追溯棧中的 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

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

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

 

window.onerror

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

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

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

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

 

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

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

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

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

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

 

try/catch

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

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

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

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

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

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

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

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

Promise

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

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

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

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

 

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

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

值得注意的是,如果 Promise 的 executor 中存在 setTimeout 語句時(shí), setTimeout 的報(bào)錯(cuò)會被全局捕獲。

 

Async Function

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

匿名函數(shù)

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

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

 

throw error

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

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

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

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

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

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

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

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

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

 

原作者:雨夜帶刀's Blog

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

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章: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)動(dòng)步數(shù)有氧達(dá)人2018-06-03

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

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

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

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

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