JavaScript異常を扱う正しい姿勢

6253 ワード

誤りは避けられないものです.適切に処理することが一番大切です.
  • 原文:Aガイドto Proper Error Handling in JavaScript Related Topics:
  • 翻訳者:Fundbug
  • 可読性を保証するために、本文は直訳ではなく意訳を採用する.また、この著作権は元の作者に帰属し、翻訳は学習にのみ使用されます.
    マーフィーの法則を信じたら、どんなことでも問題が起こると思います.コードについては、100%自信があっても大丈夫です.問題があります.この文章では、JavaScriptのエラーをどう処理するかを研究します.まず悪い処理方法、良い処理方法を紹介します.最後に非同期コードとAjaxを紹介します.
    個人的な感覚では、イベントドライブのプログラミングはJavaScript言語を非常に豊富で柔軟にしています.私たちはブラウザがイベントドライブマシンであると考えています.エラーは同じようにドライバによって発生します.エラーが発生すると、あるイベントがドロップされます.理論的に言えば、ミスはJavaScriptの中で事件です.
    これに慣れないと感じるなら、それはともかくとして.この文章の中で、私は主にブラウザの端にあるJavaScriptに関心を持っています.
    この文章はJavaScriptにおけるエラー処理部分の概念に基づいている.もしまだ慣れていないなら、先に読んでください.
    デモ
    私達が使っているデモはGitHubでダウンロードできます.プログラムは次のページが表示されます.
    誤ってTypeErrorを投げ出します.以下はこのモジュールの定義です.
    // scripts/error.js
    
    function error() {
      var foo = {};
      return foo.bar();
    }
    error()に空のオブジェクトfooが定義されているので、呼び出しfoo.bar()は、定義されていないのでエラーとして報告されます.私たちはユニットテストを使って検証します.
    // tests/scripts/errorTest.js
    
    it('throws a TypeError', function () {
      should.throws(error, TypeError);
    });
    Mochaを使ってユニットテストをしました.
    コードライブラリをクローンして、依存パッケージをインストールしたら、npm tを使ってテストを実行できます.もちろん、あるテストファイルを実行してもいいです.modules/mocha/bin/mocha tests/scripts/errorTest.js
    私を信じてください.JavaScriptのようなダイナミックな言語では、誰でもこのようなエラーに遭遇しやすいです.
    悪い処置
    ボタンに対応するイベントハンドリング関数を簡単に抽象しました.次のようになります.
    // scripts/badHandler.js
    
    function badHandler(fn) {
      try {
        return fn();
      } catch (e) { }
      return null;
    }
    Should.jsは、badHandlerでコールされるコールバック関数としてfnを受信する.私たちは対応するユニットテストを作成します.
    // tests/scripts/badHandlerTest.js
    
    it('returns a value without errors', function() {
      var fn = function() {
        return 1;
      };
    
      var result = badHandler(fn);
    
      result.should.equal(1);
    });
    
    it('returns a null with errors', function() {
      var fn = function() {
        throw new Error('random error');
      };
    
      var result = badHandler(fn);
    
      should(result).equal(null);
    });
    異常があったら、badHandlerは簡単にbadHandlerに戻るだけです.完全なコードに協力すれば、問題が発見されます.
    // scripts/badHandlerDom.js
    
    (function (handler, bomb) {
      var badButton = document.getElementById('bad');
    
      if (badButton) {
        badButton.addEventListener('click', function () {
          handler(bomb);
          console.log('Imagine, getting promoted for hiding mistakes');
        });
      }
    }(badHandler, error));
    エラーが発生したら、そのtry-catchをnullに返します.どこか間違えたところがありません.このような静かな失敗はUIの乱れを招くかもしれません.データの乱れを招くかもしれません.Debugでは何時間もかかったかもしれませんが、try-catchのコードを無視したのが原因です.コードが複雑で、多段階の呼び出しがあると、どこかに間違いがあったかもしれません.したがって、私たちは静かな失敗策を使用することを勧めません.もっと優雅な方法が必要です.
    悪くはないですが、腐った方法です.
    // scripts/uglyHandler.js
    
    function uglyHandler(fn) {
      try {
        return fn();
      } catch (e) {
        throw new Error('a new error');
      }
    }
    エラーを処理する方法はエラーを捕まえたnullです.そして、新しいエラーを投げました.このようにするのは確かに前の静かな失敗の策略より優れています.もし間違いがあったら、次々と探して帰ってもいいです.簡単にeの情報量を投げ出すのは比較的に限られています.正確ではないです.私たちは定義されたエラーオブジェクトから、より多くの情報が流れます.
    // scripts/specifiedError.js
    
    // Create a custom error
    var SpecifiedError = function SpecifiedError(message) {
      this.name = 'SpecifiedError';
      this.message = message || '';
      this.stack = (new Error()).stack;
    };
    
    SpecifiedError.prototype = new Error();
    SpecifiedError.prototype.constructor = SpecifiedError;
    
    // scripts/uglyHandlerImproved.js
    
    function uglyHandlerImproved(fn) {
      try {
        return fn();
      } catch (e) {
        throw new SpecifiedError(e.message);
      }
    }
    
    // tests/scripts/uglyHandlerImprovedTest.js
    
    it('returns a specified error with errors', function () {
      var fn = function () {
        throw new TypeError('type error');
      };
    
      should.throws(function () {
        uglyHandlerImproved(fn);
      }, SpecifiedError);
    });
    現在、このカスタムエラーオブジェクトには元々のエラーの情報が含まれていますので、より効果的になります.しかし、再び投げ出したため、依然として未処理のエラーです.
    異常を押収する
    一つの考えは、すべての関数をeで囲むことである.
    function main(bomb) {
      try {
        bomb();
      } catch (e) {
        // Handle all the error things
      }
    }
    しかし、このようなコードは非常に肥大し、読み取り不可になり、しかも効率が低下します.覚えていますか?本論文ではJavaScriptにおける異常は一つの事件に過ぎないと述べましたが、幸いにもグローバルな異常事象処理方法があります(Error('a new error')).
    // scripts/errorHandlerDom.js
    
    window.addEventListener('error', function (e) {
      var error = e.error;
      console.log(error);
    });
    スタック情報を取得
    エラー情報をサーバに送信できます.
    // scripts/errorAjaxHandlerDom.js
    
    window.addEventListener('error', function (e) {
      var stack = e.error.stack;
      var message = e.error.toString();
    
      if (stack) {
        message += '
    ' + stack; } var xhr = new XMLHttpRequest(); xhr.open('POST', '/log', true); // Fire an Ajax request with error details xhr.send(message); });
    より詳細なエラーメッセージを取得するために、データを処理する手間を省きます.また、fundebugのJavaScript監視プラグインを使って、3分間でbug監視サービスに素早くアクセスすることもできます.
    以下はサーバが受信したエラーメッセージです.
    シナリオが別のドメイン名の下に置かれている場合、try...catchを開いていないと、onerrorを除いて、有用なエラーメッセージが見えなくなります.具体的な解法を知りたいなら、Script error.を参照してください.
    非同期エラー処理CORSが非同期で実行されるため、以下のコード異常はScript error.によって捕捉されないであろう.
    // scripts/asyncHandler.js
    
    function asyncHandler(fn) {
      try {
        // This rips the potential bomb from the current context
        setTimeout(function () {
          fn();
        }, 1);
      } catch (e) { }
    }
    setTimeout文は、現在実行されている環境における異常のみをキャプチャします.しかし、上記の異常が出たときには、JavaScript解釈器はすでにtry...catchにはありませんので、捕獲できません.すべてのAjax要求も同じです.
    ちょっと改善してもいいです.try...catchを非同期関数のコールバックに書き込みます.
    setTimeout(function () {
      try {
        fn();
      } catch (e) {
        // Handle this async error
      }
    }, 1);
    しかし、このようなコースはプロジェクトの中でtry...catchに満ちています.コードが非常に簡潔ではありません.また、JavaScriptを実行するV 8エンジンは、関数にtry...catchを使用することを奨励しない.幸い、このようにする必要はありません.全体的なエラー処理try...catchはこれらのエラーを捕捉します.
    結論
    私の提案はミスを隠さずに勇敢に投げてください.コードがバグを起こして、プログラムが崩壊したことを恥じる人はいません.プログラムを中断させて、ユーザーをやり直すことができます.エラーは避けられないものです.どうやって処理するかが一番重要です.
    著作権声明:転載する時、作者のFunebugと本文の住所を明記してください.https://blog.fundebug.com/201...