Kuzunoha-NEのブログ

プログラミングなどの勉強をしてます

【JavaScript】非同期処理とTryCatch

こんにちは、葛の葉です。

JavaScriptにおける非同期処理とtry catch文についてみてみましょう。一般的に、try文内で発生したErrorはcatch文に移動します。

try {
    throw new Error('Test Error');
    console.log('hogehoge');
} catch (error) {
    console.log('piyopiyo');
}
// piyopiyo

そのエラーを検知したとき、catch文にジャンプします。ご多分の通り、throwを使うことでエラーを発生することが出来ます。すなわち、try文内において、throw文以下の命令は絶対に呼び出されることはありません。VSCodeにおいても3行目であるconsole.log('hogehoge')は到達できないと表示されます。

f:id:Kuzunoha-NE:20191107224230j:plain
到達できないコードの検出

では以下のような非同期処理においてはどうでしょうか。

try{
    setTimeout(() => {
        throw new Error('hoge');
    }, 5 * 100);
} catch (e) {
    console.log('piyopiyo');
}
/*
 /home/~~~/a.js:3
        throw new Error('hoge');
        ^

Error: hoge
*/

このように、非同期処理中に発生したエラーについてはcatchできません。

そもそもJavaScriptにはコールスタックが働いて、エラー発生時において、関数の呼び出した元の関数まで遡っていくことができます。その遡り内にtry catchがあれば、そこでエラーを検知することが出来ます。非同期処理内において発生したエラーにおいても同様にコールスタックにてエラーが遡ることになるのですが、Javascript特有のイベントループにて、非同期処理を実行する環境は各イベントのフェーズがGlobalとなるため、普段書いている同期処理内のtrycatchに引っかかることがありません。

下記のようにasyncとawaitをPromiseと組み合わせることで同期処理内にてcatchすることが出来ます。

const promise = new Promise((resolve, reject)=>{
    const hoge = 'hogehoge';
    try{
        throw new Error('ERROR DESU');
        resolve(hoge);
    }catch(e){
        reject(e);
    }
});

(async() =>{
try{
    await promise.then();
} catch (e) {
    console.log('piyopiyo');
}
})();
// piyopiyo

イマイチこのあたりが完全に理解しきれていないので、今後きちんと勉強したいです。