同期関数と非同期関数のエラーハンドリングのやり方

error-handling-sync-async-e プログラミング

※当ブログでは商品・サービスのリンク先にプロモーションを含みます。ご了承ください。

JavaScriptを触っていて、同期・非同期関数のエラーハンドリングについて曖昧なまま理解していたのが、先日ようやく自分自身の中で納得できる説明ができたので、それを書き残しておきます。

同期・非同期について曖昧な方は過去記事をよんでみてね

エラーハンドリングとは?

プログラミング実行最中に、予期せぬエラーに遭遇することがあります。

そうなった場合、プログラムがそこで中断してしまうかもしれません。

ただし、エラーハンドリングをすることで、エラーが起きても中断せずに続行をさせることができます。

JavaScriptでのエラーハンドリング

try, catch構文を使います。

try {
    const a = 1+1;
    console.log(a);
} catch(err) {
    console.log(err);
}

console.log("the world goes on");

このような感じで、エラーが起こる可能性のある処理をtryの中に記述し、投げられたエラーをcatchで獲得してくれ、そのあとの処理も続行してくれます。

例の中では、1+1の計算をしているだけですが、例えばサーバからデータをフェッチするときとか、もしかしたら失敗するかもしれない処理などをここに入れるのが正しいみたい。

同期関数のエラーハンドリングのやり方

さて、ここでややこしいのが同期と非同期のエラーハンドリングでした。全部tryの中に突っ込めばいいんじゃないの?と思ってたのですが、違いました。

同期関数の場合

同期しているということは、上から順番ずつプログラムが実行されます。

その場合は、上記で述べたようにtry, catchを記述すればOKです。

const promiseFunction = () => new Promise((resolve, reject)=>{
    setTimeout(() => {
        reject('Throw error');
      }, 300);

});

const main = async () => {
    console.log("Before try, catch");

    try {
        await promiseFunction();
    } catch(err) {
        console.log(err);
    }
    
    console.log("After try, catch");
}

main();

Promiseは非同期オブジェクトになりますが、それをasync, await同期的に処理しています。その場合は上記で説明したtry, catchで対応すれば大丈夫です。

こちらを実行すると以下が出力されます。

> Before try, catch
> Throw error
> After try, catch

試しにtry, catchをなくしてみると以下の出力になります。

> Before try, catch
> [UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Throw error".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

Before try, catchの後にすぐUnhandledPromiseRejectionを吐いてそこで実行が終わってしまいました。

非同期関数の場合

非同期しているということは、プログラムの作業が必ずしも上から下へと順番通りに実行されません

そのため、try, catchでは非同期関数をしっかりとキャッチできないかもしれないのです。

なので、こういう書き方をします。

const promiseFunction = () => new Promise((resolve, reject)=>{
    setTimeout(() => {
        reject('Throw error');
      }, 300);

});

const main = async () => {
    console.log("Before try, catch");

    promiseFunction().catch(err => console.log(err));
    
    console.log("After try, catch");
}

main();

非同期関数にcatchをチェーンしてしまいます。こうすることで、非同期にいつどこで実行されても必ずエラーをキャッチできます。

出力結果は以下です。

> Before try, catch
> After try, catch
> Throw error

まとめ

同期関数と非同期関数のエラーハンドリングについて、解説しました。

非同期の場合はどこで実行されるかわからないから、catchで紐づけてあげないとダメなんだなーと理解できました。

にほんブログ村に参加しております!よろしければクリックお願いします 🙂

にほんブログ村 IT技術ブログへ
にほんブログ村

コメント

タイトルとURLをコピーしました