JavaScript の 非同期処理(fetch / async/await) の例外処理は、初心者がつまずきやすいポイントの一つです。
ここでは、よくある「落とし穴」→「なぜダメか」→「良い書き方」を、具体コードで比較しながら、ていねいに解説します。
まず前提:同期と非同期の違い
普通の try...catch は「同期的(順番に実行される)」コードには有効ですが、
非同期処理(fetch や setTimeout, Promise) の中では注意が必要です。
目標
「非同期の中で起きたエラー」をちゃんと
catchで拾えるようにする
❌ 悪い例1:try...catch が効かないパターン
try {
fetch('https://example.com/api/data')
.then(response => {
// ネットワークエラーなどが起きても catch されない
throw new Error('APIの処理中に問題が発生');
})
.catch(err => {
console.log('Promise内部でエラー発生:', err.message);
});
} catch (e) {
console.log('外側catch:', e.message);
}
JavaScript結果
Promise内部でエラー発生: APIの処理中に問題が発生
外側の try...catch は発動しません。
なぜなら、fetch(...).then(...) は非同期で動いているから。try の中のコードが実行された時点では、まだ中の処理が終わっていないためです。
✅ 良い例1:await を使って非同期を同期的に扱う
async/await を使うと、try...catch が自然に使えます。
async function loadData() {
try {
const response = await fetch('https://example.com/api/data');
if (!response.ok) {
throw new Error(`サーバーエラー: ${response.status}`);
}
const data = await response.json();
console.log('取得成功:', data);
} catch (e) {
console.error('エラーをキャッチ:', e.message);
}
}
loadData();
JavaScriptポイント
awaitは「Promise が終わるまで待つ」→ つまり 同期的に見える。try...catchはこの「待っている間のエラー」も捕まえることができる。
❌ 悪い例2:async 関数を呼ぶ側で try...catch を忘れる
async function getUser() {
throw new Error('ユーザー情報が見つかりません');
}
try {
getUser(); // ← await を付けていない
} catch (e) {
console.log('キャッチ:', e.message);
}
JavaScript結果
Uncaught (in promise) Error: ユーザー情報が見つかりません
外側の try...catch は効きません。
理由:getUser() は Promise を返すだけで、まだエラーが発生していない(非同期中)。
✅ 良い例2:呼び出し側で await を付ける
async function getUser() {
throw new Error('ユーザー情報が見つかりません');
}
async function main() {
try {
await getUser(); // ← await 付き! これでエラーを捕まえられる
} catch (e) {
console.log('キャッチ:', e.message);
}
}
main();
JavaScriptawait を付けると、Promise の完了(成功 or 失敗)を待つため、try...catch が正しく機能します。
まとめ:非同期エラー処理の「悪い書き方」vs「良い書き方」
| 目的 | 悪い書き方 | 良い書き方 |
|---|---|---|
| Promiseチェーン中のエラー | try...catch で囲む | .catch() でハンドリングする |
| async関数内のエラー | .then().catch() で処理 | try...catch+await を使う |
| async関数を呼び出す側 | 関数() だけ呼ぶ | await 関数() で呼ぶ or .catch() を付ける |
| 同期処理と非同期処理の混在 | 同じ try にまとめる | await を使い「順番に実行」する |
実用例:fetch + async/await + エラー処理
async function fetchUser(userId) {
try {
const response = await fetch(`https://api.example.com/users/${userId}`);
if (!response.ok) {
throw new Error(`HTTPエラー ${response.status}`);
}
const data = await response.json();
console.log('ユーザー取得成功:', data);
return data;
} catch (err) {
console.error('データ取得に失敗:', err.message);
return null; // 失敗時は null など安全な値を返す
}
}
async function main() {
const user = await fetchUser(123);
if (user === null) {
console.log('再試行しますか?');
}
}
main();
JavaScript落とし穴まとめ
| 落とし穴 | 原因 | 対処法 |
|---|---|---|
try...catch で fetch のエラーが取れない | 非同期だから | await で待つ or .catch() を付ける |
async 関数を呼ぶ側で例外が無視される | await していない | 呼び出し側でも await or .catch() |
| ネットワークエラーとHTTPエラーの混同 | fetch は「通信エラー」でしか reject しない | if (!res.ok) で HTTP エラーを自前で検出 |
| 例外を throw したまま放置 | 未処理Promise警告 | 必ず try...catch or .catch() |
練習問題
問題:
次の関数はエラーを正しく捕まえていません。どこを直せばいいでしょう?
async function getData() {
const res = await fetch('https://wrong.url/api');
const data = await res.json();
console.log(data);
}
try {
getData(); // ← ここが問題
} catch (e) {
console.log('キャッチ:', e.message);
}
JavaScript👇
解答:
try {
await getData(); // await を付ける(呼び出し元も async にする)
} catch (e) {
console.log('キャッチ:', e.message);
}
JavaScriptまとめ(初心者が覚えるべきポイント)
awaitなしでは非同期エラーは捕まらないtry...catchは async関数の中で使うfetchの場合は「HTTPステータス」も自分でチェックする- 例外を「握りつぶさず」、適切に
returnorthrowで扱う

