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