快速了解JavaScript的錯誤處理

JavaScript錯誤處理.png

編程語言都會需要完善的錯誤處理策略使得應用程序更為合理的操作錯誤。錯誤處理在服務端的處理較為完善,但是瀏覽器端進展較為緩慢,不同瀏覽器的錯誤處理方式也不同,且默認的錯誤處理方式對用戶也不友好。因此,必須理解各種捕獲和處理錯誤的方式。而在 ECMA-262 的第3版中增加了 try-catch 語句塊和 throw 語句來處理錯誤,以及一些錯誤類型來描述錯誤。

try-catch

ECMA-262 新增的錯誤處理方式與 Java 相似,將可能出錯的代碼放在 try 子句中,而處理錯誤的代碼放在 catch 子句中:

try {
    // Possible error code
} catch (e) {
    // Error Handler
}

catch 子句中捕獲到的錯誤對象包含發(fā)生錯誤的相關信息,通過該錯誤對象可以獲取錯誤類型的 name 屬性和保存錯誤消息的 message 屬性,e.message 即可調(diào)用。

在使用 try-catch 語句塊時,要知道什么時候使用最好。如果發(fā)生無法控制的錯誤上,就需要使用 try-catch 語句塊來處理錯誤;如果明確知道代碼會發(fā)生某種錯誤,就要采用相應的操作來防止錯誤發(fā)生,而不是使用 try-catch 語句塊來處理錯誤。

finally

try-catch 語句塊中,無論是 try 子句執(zhí)行完,還是 catch 子句執(zhí)行完,都可以接著執(zhí)行 finally 子句中的代碼,trycatch 都無法阻止,包括 return 語句。

function test(){
    try {
        return 1;
    } catch (e){
        throw e;
    } finally {
        return false;
    }
}

上面的方法,最后會返回 false。

<small>注意:主要代碼中包含了 finally 子句,try 塊或 catch 塊中的 return 語句就會被忽略,理解這一點很重要。在使用 finally 時一定要仔細確認代碼的行為。</small>

拋出錯誤

使用 throw 拋出錯誤是另一種錯誤處理方式。throw 拋出任意表達式。如下所示:

throw "Not Value Error";        // String type error
throw 31;                       // Number type error
throw false;                    // Boolean type error
throw { name: "JavaScript" };   // Object type error

也可以調(diào)用 Error 構造函數(shù)來生成一個錯誤對象拋出,接收的值為錯誤消息。如下所示:

throw new Error("Null value Error.");

也可以調(diào)用特定的錯誤類型生成一個錯誤對象并拋出。如 SyntaxError、TypeError 等。使用 ES6 中的繼承語法創(chuàng)建錯誤類型也可以,這樣需要提供 name 屬性和 message 屬性。如下所示:

class CustomError extends Error {
    constructor(message) {
        super(message);
        this.name = "CustomError";
        this.message = message;
    }
}
throw new CustomError("Null Value Error.");

這種方式有助于在捕獲錯誤時更精準地區(qū)分錯誤。

Error

Error 錯誤類型是基本類型,其它錯誤類型基本都是繼承該類型。Error 提供了一個構造方法用來創(chuàng)建實例對象,當發(fā)生錯誤時,Error 通過構造方法創(chuàng)建實例對象并被拋出。

throw new Error("Null Value Error.");

Error 錯誤類型提供了三個屬性:

  • name:字符串類型。表示錯誤名稱。
  • message:字符串類型。表示錯誤信息。
  • stack:字符串類型。表示錯誤的堆棧。

ECMA-262 總共定義了 8 種錯誤類型,除了 Error 通用的錯誤類型外,還有如下幾種類型:

  • EvalError:該錯誤類型會在使用 eval() 函數(shù)發(fā)生錯誤時拋出。
  • InternalError:該錯誤類型主要會在底層 JavaScript 引擎拋出異常時由瀏覽器拋出。如遞歸過多導致棧溢出。通常并不是需要處理的錯誤。
  • RangeError:該錯誤類型會在數(shù)值變量或參數(shù)越界時拋出。
  • ReferenceError:該錯誤類型會在引用無效時拋出。
  • SyntaxError:該錯誤類型會在 eval() 在解析代碼的過程中發(fā)生。
  • TypeError:該錯誤類型會在變量或參數(shù)不是預期類型,或者訪問不存在的方法時拋出。
  • URIError:該錯誤類型只會在使用 encodeURI()decodeURI() ,并且傳入的 URI 格式錯誤時發(fā)生。

瀏覽器很少會拋出 Error 類型的錯誤,主要是開發(fā)者拋出的自定義錯誤。而其它錯誤類型可以使用 instanceof 進行判斷。如下所示:

try {
    // Possible error code
} catch (e) {
    if (e instanceof TypeError) {
        // Type Error Handler
    } else if (e instanceof ReferenceError) {
        // Reference Error Handler
    } else {
        // Other Error Handler
    }
}

error 事件

沒有被 try-catch 捕獲的錯誤都會在 window 對象上觸發(fā) error 事件。該事件會傳入幾個參數(shù):

  • message:錯誤消息。
  • url:發(fā)生錯誤的 URL
  • line:錯誤的行號。
  • colno:錯誤的列號。
  • errorError對象。
window.onerror = (message, url, line, colno, error) => {
    // 可以對錯誤的消息進行處理,這里打印在控制臺上
    console.log(message);
    return false; // 這里返回 false 來阻止瀏覽器默認報告錯誤的行為
};

通過返回 false,函數(shù)實際上變成整個文檔的 try/catch 語句,可以捕獲所有未處理的運行時錯誤。適當?shù)?try-catch 語句塊意味著不會有錯誤到達瀏覽器這個 層次,因此就不會觸發(fā) error 事件。當返回 true,會阻止執(zhí)行默認事件處理函數(shù)。

而有一些資源加載失敗,會觸發(fā)一個 error 事件,這個事件遵循 DOM 格式。因此可以使用 addEventListener 捕獲。

const image = new Image();
image.addEventListener("error", (event) => {
    console.log("Image not loaded!");
});
image.src = "resource.gif"; // 不存在,資源會加載失敗。

總結

一個設計良好的錯誤處理對編程語言十分重要。JavaScript 提供的 try-caththrow 兩種處理錯誤的方式。但是兩種錯誤處理方式,有不同的錯誤場景要求。如果編寫的庫或函數(shù)需要知道錯誤發(fā)生的具體原因,就拋出異常;如果確切知道接下來的操作,就捕獲錯誤。而沒有通過 try-catch 處理的錯誤,可以使用 window.onerror 事件來處理。

更多內(nèi)容請關注公眾號「海人為記

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容