JavaScript | 非同期エラーの「良い書き方・悪い書き方」を比較するサンプル

JavaScript
スポンサーリンク

ここでは、「非同期処理での例外(エラー)をどう扱うか」について、
初心者がよくやってしまう「悪い書き方」と、実務的に安全な「良い書き方」を、
コメント付きで比較解説
します。


テーマ:setTimeout などの「非同期処理」の中でエラーが出たときの違い

❌ 悪い書き方(try…catch が効かない例)

console.log("Start");

try {
  // setTimeoutは「1秒後に関数を呼ぶ」だけ。
  // この時点では何も起きない。
  setTimeout(() => {
    console.log("実行中...");
    // ここでエラー発生!
    throw new Error("Big trouble!");
  }, 1000);
} catch (e) {
  // ⚠️ この catch は呼ばれない!
  console.error("捕まえた(はず):", e.message);
}

console.log("End");
JavaScript

🧠 解説:

  • setTimeout の中の関数は「後で(1秒後)」実行されます。
  • つまり、try が終わってから実行されるため、外側の catch はもう無効です。
  • 実行結果:
Start
End
Uncaught Error: Big trouble!   ← 外側で捕まえられない

💬 「try…catch で囲ってるのに捕まらない!?」という罠。
非同期処理では、この書き方では 例外が外に逃げてしまう のです。


✅ 良い書き方①(コールバック内で try…catch)

console.log("Start");

setTimeout(() => {
  try {
    console.log("実行中...");
    throw new Error("Big trouble!");
  } catch (e) {
    console.error("✔ コールバック内で捕まえた:", e.message);
  }
}, 1000);

console.log("End");
JavaScript

出力:

Start
End
実行中...
✔ コールバック内で捕まえた: Big trouble!

🧠 解説:
非同期処理の中では、その中(コールバック関数内)に try…catch を置くのが確実です。
外の try に頼らないのがポイント。


✅ 良い書き方②(Promise + .catch)

// 非同期処理を Promise でラップする
function asyncTask() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("実行中...");
      // 失敗したら reject
      reject(new Error("Big trouble!"));
    }, 1000);
  });
}

console.log("Start");

asyncTask()
  .then(result => console.log("成功:", result))
  .catch(err => console.error("✔ Promiseで捕まえた:", err.message));

console.log("End");
JavaScript

出力:

Start
End
実行中...
✔ Promiseで捕まえた: Big trouble!

🧠 解説:

  • Promise は「成功時(resolve)」と「失敗時(reject)」を明確に分けられます。
  • .catch() で失敗を確実に捕まえられるので、外側の try に頼る必要がありません。

✅ 良い書き方③(async/await + try…catch)

// Promise を返す非同期関数
function asyncTask() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log("実行中...");
      reject(new Error("Big trouble!"));
    }, 1000);
  });
}

// async 関数で同期っぽく書ける
async function main() {
  console.log("Start");

  try {
    const result = await asyncTask();
    console.log("成功:", result);
  } catch (e) {
    console.error("✔ async/awaitで捕まえた:", e.message);
  }

  console.log("End");
}

main();
JavaScript

出力:

Start
実行中...
✔ async/awaitで捕まえた: Big trouble!
End

🧠 解説:

  • await は Promise の完了を「待つ」構文。
  • try…catch の中で使えば、非同期でも同期と同じように例外を処理できます。
  • 実務でも最も使われる、安全で読みやすい書き方です。

まとめ表

パターン説明エラーを捕まえられる?推奨度
❌ 外側 try…catch で setTimeout を囲む非同期の中では無効× 捕まえられない🚫
✅ コールバック内で try…catch確実に捕まえる○ 捕まえられる👍
✅ Promise + .catch非同期処理の基本形○ 捕まえられる👍👍
✅ async/await + try…catch一番読みやすく実務的○ 捕まえられる🌟最高

実務的アドバイス

  • setTimeout, fetch, イベントリスナーなど**「あとで実行される」処理**は、基本的に外の try では捕まらないと思ってください。
  • 非同期処理の中に try…catch を入れるか、Promise/.catch で受ける。
  • もし複数の非同期処理を組み合わせるなら、async/await でまとめるのがおすすめです。
タイトルとURLをコピーしました