では、try…catch が 関数呼び出しの先で例外が起きた場合 と 非同期(コールバック)での例外 を初心者向けに噛み砕いて、たくさんの例題と出力例つきで詳しく説明します。
基本イメージ
try { … } catch (e) { … }は「試して(try)、もし例外が出たら捕まえて(catch)処理する」仕組みです。tryの中で「例外が発生する可能性のある処理」を囲います。
1) 同期関数を呼び出して、その内部で例外が起きたとき
ポイント: 呼び出し元の try の中で関数を呼んでいるなら、その関数内でエラーが起きても呼び出し元の catch で捕まえられます。
例①(単純)
function sum(a, b) {
return a + b;
}
console.log('Start');
try {
console.log(sum(10, 8)); // 正常: 18
console.log(sum(10, 8n)); // ここで TypeError (BigInt と Number の混在)
} catch (e) {
console.error('caught:', e.message);
}
console.log('End');
JavaScript出力(想定)
Start
18
caught: Cannot mix BigInt and other types, use explicit conversions
End
説明:sum(10, 8n) のように BigInt と Number を混ぜると TypeError が出ますが、呼び出しを try の中に書いているので catch で処理され、プログラムは止まりません。
2) 関数が入れ子(多段)になっている場合
ポイント: 例外は呼び出し元に伝搬(スタックをさかのぼる)して、どこかに try…catch があればそこで捕まえられます。
例②(多段)
function inner(a, b) {
return a + b; // ここで例外が起きる可能性(例:BigInt 混在)
}
function middle(a, b) {
return inner(a, b);
}
function outer(a, b) {
return middle(a, b);
}
console.log('Start');
try {
console.log(outer(10, 8n)); // innerで例外 → outerをさかのぼってcatchで捕まる
} catch (e) {
console.error('caught at outer:', e.message);
}
console.log('End');
JavaScript出力(想定)
Start
caught at outer: Cannot mix BigInt and other types, use explicit conversions
End
3) 注意! 非同期のコールバック関数では try…catch が効かない場合がある
重要ポイント(ここで多くの初心者が混乱します):setTimeout やイベントハンドラなど、非同期に後から呼ばれる関数の中で起きた例外は、外側の try では捕まえられないことがあります。なぜなら、try が実行されているときと、コールバックが実行されるタイミングが別(時間差がある)だからです。
例③(NGパターン)
console.log('Start');
try {
setTimeout(function sum(a, b) {
// 1秒後に実行される
console.log(a + b); // ここで BigInt 混在なら例外
}, 1000, 10, 8n);
} catch (e) {
console.error('caught:', e);
}
console.log('End');
JavaScript実行の流れ(想定)
Start
End
// 1秒後にコールバックが実行され、ここで例外が発生すると
// ブラウザ/ランタイムの「Uncaught TypeError: ...」が出る(外側の catch では捕まらない)
説明:setTimeout 呼び出し自体は同期にすぐ終了する(コールバック呼出しは後)ため、コールバック内の例外は外側の try のスコープ外で発生します。よって外側の catch で捕まえられません。
4) 非同期で例外を安全に扱う方法(実践的な対策)
ここからは実用的な回避策をいくつか示します。どれを使うかは状況に依ります。
A. コールバックの中で個別に try…catch を書く(最も単純)
setTimeout(function (a, b) {
try {
console.log(a + b); // ここで例外が起きてもローカルで処理可能
} catch (e) {
console.error('caught inside callback:', e.message);
}
}, 1000, 10, 8n);
JavaScriptB. Promise を使い .catch() で受ける(モダン)
非同期処理が Promise を返すなら、.catch() でエラーを受け取れます。現代的には fetch, async 関数などと相性が良いです。MDN のドキュメントも参考にしてください。
// サンプルの疑似非同期処理を Promise 化
function asyncAdd(a, b) {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
resolve(a + b);
} catch (e) {
reject(e);
}
}, 500);
});
}
asyncAdd(10, 8n)
.then(result => console.log(result))
.catch(err => console.error('promise caught:', err.message));
JavaScriptC. async/await と try…catch を組み合わせる(同期風に書けてわかりやすい)
async 関数内で await しているときは、通常の try…catch で例外(Promise の rejected)を捕まえられます。MDN 参照。
async function doAdd() {
try {
const result = await asyncAdd(10, 8n);
console.log(result);
} catch (e) {
console.error('async/await caught:', e.message);
}
}
doAdd();
JavaScriptD. (補助的)Promise.try / Promise.resolve を使う
最近は Promise.try() のようなユーティリティが使える場面もあり、同期関数の「即時スロー」を Promise の拒否に変換するのに便利です(環境依存)。参考記事あり。
5) 実践的なチェックリスト(初心者がコードを書くときの習慣)
- その処理は同期? 非同期? をまず判断する。
- 同期 → 呼び出し元の
tryで捕まえられる。 - 非同期 → コールバックのなかで
tryを使うか、Promise/.catch、async/await を使う。
- 同期 → 呼び出し元の
- 非同期で外側の
tryに頼らない(頼ってもうまく捕まらないことがある)。 - 外部 API 呼び出しやファイル処理など「失敗の確率がある処理」は必ずエラー処理を入れる(ユーザーにエラーメッセージを出す、再試行する、ログを残す等)。
6) 練習問題(自分で試してみよう)
問1. 下のコードを実行して、どこの catch でエラーが捕まるか予想し、実行して確かめてください。
function a() { b(); }
function b() { c(); }
function c() { throw new Error('boom'); }
try {
a();
} catch (e) {
console.log('caught at top:', e.message);
}
JavaScript(期待)caught at top: boom
問2. 次のコードは外側の catch でエラーを捕まえられるか? 実行して確かめてください。
try {
setTimeout(() => { throw new Error('later boom'); }, 100);
} catch (e) {
console.log('caught outer:', e.message);
}
JavaScript(期待)外側の catch では捕まらず、コンソールに Uncaught Error: later boom のように表示される。対処法としてはコールバック内で try を使うか Promise 化して .catch() すること。
問3. async/await で fetch 等の例を作り、try…catch でエラーを処理してみる(実際の API を使うか、Promise.reject(new Error('fail')) を作って試す)。
まとめ(初心者向け)
- 同期関数のエラー → 呼び出し元の
tryで捕まる(伝搬する)。 - **非同期(コールバック)**のエラー → 外側の
tryでは捕まらないことがある。コールバック内でtry、または Promise/.catch、async/await を使おう。 - 実際に手を動かして、上の例をブラウザのコンソールや Node.js で試すと理解が早いです。

