JavaScript >> Javascript 文檔 >  >> Tags >> Error

JavaScript 錯誤處理反模式

我覺得缺乏足夠討論的領域之一是 JavaScript 中的錯誤處理。雖然服務器軟件中的錯誤處理通常有很多想法,包括錯誤日誌和監控系統,但對 JavaScript 的關注卻很少。我試圖通過我的 Ajax 體驗演講“企業 JavaScript 錯誤處理”來提高對這一點的認識,其中我討論了錯誤處理方法以及常見的錯誤源。

我在演講中的一個建議是為您的應用程序提供調試模式。這個想法是生產模式對用戶隱藏 JavaScript 錯誤並適當地處理它們,而調試模式允許錯誤冒泡到瀏覽器級別並像往常一樣報告。當然,後者對於調試目的很重要。當瀏覽器中彈出錯誤時,您可以選擇使用所有周圍的上下文信息進行調試。我在演講中建議的模式如下所示:

function doSomething(value){
    try {
        process(value);
    } catch (ex){
        if (debugMode){
            throw ex;
        } else {
            log(1, "doSomething(): " + ex.message);
        }
    }
}

這裡的想法是捕獲錯誤,並根據模式執行適當的操作。正如開發中經常發生的那樣,我現在發現這不是最好的方法,實際上會帶來痛苦的後果。

如果 process() 發生錯誤 ,該錯誤被捕獲並從 doSomething() 拋出 ,這會破壞調用堆棧。該錯誤現在與實際事件相距太遠,無法用於調試。一旦執行退出 process(),所有可能導致解決方案的上下文信息都將丟失 .想像一下,讓您的調試器設置為在所有錯誤上中斷:使用此代碼,中斷將發生在包含 throw ex 的行上 當您真的希望它在 process() 內部中斷時 因為這才是真正的問題所在。

我現在認為這是一種錯誤處理反模式,一種阻止有用調試而不是啟用它的模式。我現在推薦的模式是完全刪除 try-catch 處於調試模式時的語句。這允許正常的代碼執行,並在發生錯誤時導致正確的調用堆棧放置。有幾種方法可以實現這種模式,第一種是看起來相當難看的條件語句:

function doSomething(value){
    if (debugMode){
        process(value);
    } else {
        try {
            process(value);
        } catch (ex){
            log(1, "doSomething(): " + ex.message);
        }
    }
}

第二種可以說更優雅的方法是根據執行模式簡單地替換整個函數:

var doSomething = debugMode ?
    function(value){
        process(value);
    } :
    function(value){
        try {
            process(value);
        } catch (ex){
            log(1, "doSomething(): " + ex.message);
        }
    };

這是我的首選方法,因為它消除了檢查 debugMode 每次執行函數時。此外,這種方法很容易實現自動化。假設您有一個或多個對象,並且您希望它們的所有方法在生產中都有一個包裝器來捕獲錯誤。下面的代碼很容易做到這一點:

//by Nicholas C. Zakas (MIT Licensed)
function productionize(object){

    var name,
        method;

    for (name in object){
        method = object[name];
        if (typeof method == "function"){
            object[name] = function(name, method){
                return function(){
                    try {
                        return method.apply(this, arguments);
                    } catch (ex) {
                        log(1, name + "(): " + ex.message);
                    }
                };

            }(name, method);
        }
    }
}

此代碼迭代對象的屬性並將每個函數替換為另一個包含適當錯誤處理機制的函數。你可以這樣使用函數:

var system = {
    fail: function(){
        throw new Error("Oops!");
    }
};

function log(severity, message){
    alert(severity + ":" + message);
}

if (!debugMode){
    productionize(system);
}

system.fail();   //error is trapped!

這種錯誤捕獲模式將在難以追踪錯誤的複雜環境中為您提供良好的服務。確保從正確的地方拋出錯誤是調試問題的第一步。


Tutorial JavaScript 教程
  1. Angular 構建上傳到 AWS S3 + Cloudfront

  2. 使用 OffscreenCanvas 和 Web Worker 實現更快的 WebGL/Three.js 3D 圖形

  3. React 中的全局與本地狀態

  4. 在 React 中使用 Web Share API

  5. 了解 Node.js 中的工作線程

  6. 需要節點 - 第 1 卷

  7. Javascript 承諾

  1. 使用 Node.js 開始使用 AWS SQS - 第 1 部分

  2. 反應鉤子:useRef

  3. 第 3 天:學習開始

  4. Javascript – 卡在 if 語句中 – 初學者問題

  5. 如何在電子 nodejs 中創建自定義字母字符映射

  6. 電子大冒險:第 42 集:Marko 文件管理器

  7. 通過 isomorphic-unfetch 獲取時 nextjs api 不起作用

  1. Crieit的文章詳情頁成為日本技術發帖服務最快的

  2. Javascript DOM

  3. 一個 Chrome 應用程序來統治他們(付費牆):第 1 部分

  4. 如何最大化您作為遠程工程師的工作機會