JavaScriptの異常処理


JavaScriptエンジンがJavaScriptコードを実行すると、様々な異常が発生する可能性があります.例えば文法異常、言語に不足している機能は、サーバやユーザからの異常な出力に起因する異常があります.
Javascriptエンジンはシングルスレッドですので、異常が発生すると、Javascriptエンジンは通常実行を停止し、後続のコードをブロックし、異常な情報を投げるので、予測可能な異常についてはユーザーまたは開発者にキャプチャして正確に示すべきです.
Errオブジェクト
throwとPromise.reject()は、文字列タイプの異常を抛り出すことができ、また、Errオブジェクトタイプの異常を投げることができます.
Errオブジェクトタイプの異常には異常な情報が含まれているだけでなく、追跡スタックも含まれています.そうすると、追跡スタックを通してコードエラーの行数を見つけやすくなります.
したがって、文字列タイプの異常ではなく、Errオブジェクトタイプの例外を持ち出すことを推奨します.
自分の異常な構造関数を作成します.
function MyError(message) {
    var instance = new Error(message);
    instance.name = 'MyError';
    Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
    return instance;
}

MyError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: MyError,
        enumerable: false,
        writable: true,
        configurable: true
    }
});

if (Object.setPrototypeOf) {
    Object.setPrototypeOf(MyError, Error);
} else {
    MyError.__proto__ = Error;
}

export default MyError;
ユーザー定義の異常タイプをコードに投げて捕らえる
try {
    throw new MyError("some message");
} catch(e){
    console.log(e.name + ":" + e.message);
}
Throw
throw expression; 
throw文はユーザーがカスタマイズした異常をスローします.現在の関数の実行は停止されます.(throw以降のステートメントは実行されません.)制御は、スタックの最初のcatchブロックを呼び出します.使用者関数にcatchブロックがない場合、プログラムは終了します.
try {
    console.log('before throw error');
    throw new Error('throw error');
    console.log('after throw error');
} catch (err) {
    console.log(err.message);
}

// before throw error
// throw error
Try/Catch
try {
   try_statements
}
[catch (exception) {
   catch_statements
}]
[finally {
   finally_statements
}]
try/catchは主に異常をキャッチするために使われます.try/catch文は一つのtryブロックと少なくとも一つのcatchブロックまたは一つのfinallyブロックを含み、以下は三つの形のtry声明である.
  • try…catch
  • try...finally
  • try...catch...finally
  • tryブロックに入れると、異常な語句や関数が発生する可能性があります.
    catchブロックには実行する語句が含まれています.tryブロックに異常があると、catchブロックはこの異常情報を捉えて、catchブロックのコードを実行します.tryブロックに異常がなければ、このcatchブロックはスキップします.
    finallyブロックはtryブロックとcatchブロックの後に実行される.異常があるかどうかは別として、投げたり、捕獲されたりするかどうかは常に実行されます.finallyブロックに異常情報がドロップされるとtryブロック中の異常情報が上書きされます.
    try {
        try {
            throw new Error('can not find it1');
        } finally {
            throw new Error('can not find it2');
        }
    } catch (err) {
        console.log(err.message);
    }
    
    // can not find it2
    finallyブロックから値を返すと、この値はtry-catch-finally全体の戻り値となり、return文があるかどうかにかかわらずtryとcatch中にある.これはcatchのブロックから投げられた異常を含んでいます.
    function test() {
        try {
            throw new Error('can not find it1');
            return 1;
        } catch (err) {
            throw new Error('can not find it2');
            return 2;
        } finally {
            return 3;
        }
    }
    
    console.log(test()); // 3
    Try/Catch性能
    よく知られているアンチ最適化モデルはtry/catchを使っています.
    V 8(他のJSエンジンも同じ場合があります.)関数でtry/catch文を使ってV 8コンパイラに最適化できません.http://www.html5rocks.com/en/tutorials/speed/v8/を参照してください
    window.onerror
    window.onerrorでイベント傍受関数を定義することによって、プログラム内の他のコードから発生した捕獲されていない異常は、よくwindow.onerror上に登録された傍受関数によって捉えられます.そして異常に関するいくつかの情報を同時に捕獲した.
    window.onerror = function (message, source, lineno, colno, error) { }
  • message:異常情報(文字列)
  • source:異常が発生したスクリプトURL(文字列)
  • lineno:異常が発生した行番号(数字)
  • colno:異常が発生した列番号(数字)
  • error:Errオブジェクト(オブジェクト)
  • 注意:SafariとIE 10はまだwindow.onerrorのコールバック関数で5番目のパラメータを使用していません.つまりErrオブジェクトであり、追跡スタックを持っています.
    try/catchは非同期コードの異常を捕獲できませんが、異常をグローバルに投げてwindow.onerrorで捕獲できます.
    try {
        setTimeout(() => {
            throw new Error("some message");
        }, 0);
    } catch (err) {
        console.log(err);
    }
    // Uncaught Error: some message
    window.onerror = (msg, url, line, col, err) => {
        console.log(err);
    }
    setTimeout(() => {
        throw new Error("some message");
    }, 0);
    // Error: some message
    Chromeでは、window.onerrorは、他のドメインから引用されたscriptファイルの異常を検出し、これらの異常をScript errorとしてマークすることができる.これらが他のドメインから導入されたscriptファイルを処理したくないなら、プログラム中にScript errorタグでフィルタリングしてもいいです.しかしながら、Firefox、SafariまたはIE 11においては、ドメインをまたぐJS異常は導入されず、Chromeにおいても、try/catchを使用してこれらの嫌なコードを囲むと、Chromeはこれらのクロスドメイン異常を検出しない.
    Chromeでは、window.onerrorを通じて完全なクロスドメイン異常情報を取得するには、これらのクロスドメインリソースは適切なクロスドメインヘッダ情報を提供する必要があります.
    Promise中の異常
    Promise中に投げた異常
    new Promise((resolve,reject)=>{
        reject();
    })
    Promise.resolve().then((resolve,reject)=>{
        reject();
    });
    Promise.reject();
    throw expression; 
    Promiseで異常をキャッチ
    promiseObj.then(undefined, (err)=>{
        catch_statements
    });
    promiseObj.catch((exception)=>{
        catch_statements
    })
    JavaScript関数では、return/yield/throwだけが関数の実行を中断します.他のものはすべて最後まで運行を停止できません.
    reolve/rejectの前にreturnを加えると、次の運転を止めることができます.
    without return:
    Promise.resolve()
    .then(() => {
        console.log('before excute reject');
        reject(new Error('throw error'));
        console.log('after excute reject');
    })
    .catch((err) => {
        console.log(err.message);
    });
    
    // before excute reject
    // throw error
    // after excute reject
    use return:
    Promise.resolve()
    .then(() => {
        console.log('before excute reject');
        return reject(new Error('throw error'));
        console.log('after excute reject');
    })
    .catch((err) => {
        console.log(err.message);
    });
    
    // before excute reject
    // throw error
    Throw or Reject
    try/catchでもpromiseでも捕獲できるのは「同期」異常です.
    rejectはコールバックであり、throwは同期されたステートメントでしかないので、別の非同期のコンテキストでドロップすると、現在のコンテキストではキャプチャできません.
    そのためPromiseでrejectを使って異常を投げます.catchは捕まえられないかもしれません.
    Promise.resolve()
    .then(() => {
        setTimeout(()=>{
            throw new Error('throw error');
        },0);
    })
    .catch((err) => {
        console.log(err);
    });
    
    // Uncaught Error: throw error
    Promise.resolve()
    .then(() => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject(new Error('throw error'));
            }, 0);
        });
    })
    .catch((err) => {
        console.log(err);
    });
    
    // Error: throw error
    window.onunhandledrejectionwindow.onunhandledrejectionwindow.onerrorと同様に、JavaScript Promiseがrejectによってキャプチャされていないが、このrejectをキャプチャーする際にトリガされる.そして異常に関するいくつかの情報を同時に捕獲した.
    window.onunhandledrejection = event => { 
        console.log(event.reason);
    }
    eventイベントはPromiseRejectionイベントの例であり、2つの属性がある.
  • event.promise:レジェクトのJavaScript Promise
  • event.reason:1つの値またはObjectは、Promise.rejectの内容である理由を示しています.
  • window.rejection handed
    Promiseはcatchメソッドを後で呼び出すことができるので、rejectを投げる時にcatchを呼び出してキャプチャしないと、後で再度catchを呼び出すと、rejection handedイベントが発生します.
    window.onrejectionhandled = event =>
    {
        console.log('rejection handled');
    }
    
    let p = Promise.reject(new Error('throw error'));
    
    setTimeout(()=>{
        p.catch(e=>{console.log(e)});
    },1000);
    
    // Uncaught (in promise) Error: throw error
    // 1    
    // Error: throw error
    // rejection handled
    統一異常処理
    コードから投げられた異常の一つは、開発者に見せることです.
    ユーザーに示される異常については、一般的にalertまたはtoastを使用して示す.開発者に展示されている異常は、コンソールに出力されます.
    一つの関数または一つのコードブロックにおいて、投げられた異常を統一的に捉えることができます.
    クリックして確認したい異常タイプ:ensureError.js
    function EnsureError(message = 'Default Message') {
        this.name = 'EnsureError';
        this.message = message;
        this.stack = (new Error()).stack;
    }
    EnsureError.prototype = Object.create(Error.prototype);
    EnsureError.prototype.constructor = EnsureError;
    
    export default EnsureError;
    ポップウィンドウヒントの異常タイプ:toastErrror.js
    function ToastError(message = 'Default Message') {
        this.name = 'ToastError';
        this.message = message;
        this.stack = (new Error()).stack;
    }
    ToastError.prototype = Object.create(Error.prototype);
    ToastError.prototype.constructor = ToastError;
    
    export default ToastError;
    ヒント開発者の異常タイプ:devError.js
    function DevError(message = 'Default Message') {
        this.name = 'ToastError';
        this.message = message;
        this.stack = (new Error()).stack;
    }
    DevError.prototype = Object.create(Error.prototype);
    DevError.prototype.constructor = DevError;
    
    export default DevError;
    異常プロセッサ:普通の異常を持ち出した場合、stackoverflow上の問題のリストを持って、開発者が原因を探しやすいです.error Handler.js
    import EnsureError from './ensureError.js';
    import ToastError from './toastError.js';
    import DevError from './devError.js';
    import EnsurePopup from './ensurePopup.js';
    import ToastPopup from './toastPopup.js';
    
    function errorHandler(err) {
        if (err instanceof EnsureError) {
            EnsurePopup(err.message);
        } else if (err instanceof ToastError) {
            ToastPopup(err.message);
        }else if( err instanceof DevError){
            DevError(err.message);
        }else{
            error.message += ` https://stackoverflow.com/questions?q=${encodeURI(error.message)}`
            console.error(err.message);    
        }
    }
    
    window.onerror = (msg, url, line, col, err) => {
        errorHandler(err);
    }
    
    window.onunhandledrejection = event =>{
        errorHandler(event.reason);
    };
    
    export default errorHandler;
    いらっしゃいませ.Leechikit原文のリンク:segmentfault.com
    ここで終わります.質問と指摘を歓迎します.オリジナルの文章を書くのは簡単ではないです.この文章があなたのために役立つなら、作者の支持を称賛し、推薦し、注目してください.