1. id が 1 の作品を読み込めた
  2. 無い id は失敗として受け止める
  3. 空の配列でも落ちずに失敗を返す
  4. 非公開の作品でも id が合えば読み込める
コース一覧
非同期JavaScript:API通信とモジュール
非同期のエラーを捕まえる

非同期JavaScript:API通信とモジュール

Promise と async/await、非同期エラー、HTTP/REST、fetch による GET、読み込み・成功・失敗の表示、モジュールの読み方を学ぶ全 19 レッスン(380 分)のコースです。最後は承認済みの読み取り専用 API から作品データを取得して表示します。POST はリクエストの組み立てまでで、外部サービスへの書き込みは行いません。

1
非同期処理
01. 同期と非同期15分
02. Promise をつくって返す20分
03. async と await20分
04. Promise.all で同時に待つ20分
05. 非同期のエラーを捕まえる20分
06. つくる 読み込み中の表示を出す30分
07. 第1章まとめクイズ10分
2
fetch で外のデータを使う
01. HTTP と REST の読みかた15分
02. fetch でデータを取る25分
03. 取ったデータを描画する25分
04. response.ok と失敗時の表示25分
05. POST のリクエストを組み立てる20分
06. つくる 作品データを API から読む30分
07. 第2章まとめクイズ10分
3
モジュールと総仕上げ
01. ファイルを分けるという考えかた15分
02. named export と default export15分
03. つくる ポートフォリオアプリを仕上げる40分
04. ここから先の学びかた15分
05. 第3章まとめクイズ10分

非同期のエラーを捕まえる

catch まで届く失敗、届かない失敗
解説

このレッスンで分かること

  • 失敗した Promise を await すると、その行で例外が投げられます
  • await を書き忘れると、try で囲んでも失敗をすり抜けます

catch を書いたのに、失敗がすり抜ける

非同期の失敗でいちばん多い事故は、try の書き方ではなく await の書き忘れです。下のコードは try で囲んであるのに、catch はいつまでも動きません。

JavaScript

async function readBio(profileId) { try { const bio = fetchBio(profileId); // await が無い return bio.text; } catch (error) { return "自己紹介はまだありません"; } }

await が無いので bio に入るのは箱そのものです。bio.text は undefined になり、そのまま return まで進みます。箱が失敗の返事を出すのはそのあとで、try はもう抜けたあとです。失敗はどこにも受け止められず、画面には何も起きず、原因も分からないという最悪の形になります。

同じことが return fetchBio(profileId); でも起きます。try の中に書いてあっても、箱をそのまま返しているので、失敗するのは呼ばれた側を抜けたあとです。try の中で受け止めたいなら return await と書きます。

失敗という返事を作る

Promise の返事は 2 通りでした。成功が resolve、失敗が reject です。reject に渡すのは Error のオブジェクトにします。

JavaScript

function fetchBio(profileId) { return new Promise(function (resolve, reject) { setTimeout(function () { if (!profileId) { reject(new Error("プロフィールが指定されていません")); return; } resolve("Web エンジニアを目指しています"); }, 80); }); }

reject を呼んだあとの return に注目してください。reject は関数から抜ける構文ではないので、書かないと下の resolve まで届いてしまいます。確定した箱は動かないので実害は出ませんが、読む人には迷子の行に見えます。

起きたことawait した行の動きどこで受けるか
resolve された中身が変数に入る次の行へ進む
reject された例外が投げられる同じ try の catch
どちらも呼ばれない再開しないどこでも受けられない

3 行目が非同期ならではの落とし穴です。確定しない箱は失敗ですらありません。エラーも出ないまま関数が止まったままになり、採点では時間切れとして扱われます。

失敗しても、同じ形の値を返す

reject された箱を await すると、その行で例外が投げられます。同期の throw とまったく同じ扱いなので、受け止め方も同じです。

JavaScript

async function readBio(profileId) { try { return await fetchBio(profileId); } catch (error) { return "自己紹介はまだありません"; } }

catch が受け取る error は、reject に渡した Error オブジェクトそのものです。error.message で文章を取り出せます。

ここで大事なのは、成功しても失敗しても同じ形の値を返しているところです。片方は文字列、片方は undefined という関数にすると、呼ぶ側に「どちらだったか」を確かめる分岐が増えます。失敗の面倒を見た関数が、外へ面倒を持ち出さない形にしておいてください。

解説

new Promise を書かず、async function の中で直接 throw することもできます。投げた例外は、その関数が返す Promise の失敗としてそのまま外へ出るので、呼ぶ側から見れば reject されたときと同じです。

よくある間違い

  • reject に文字列を渡す — reject("見つかりません") と書くと error は文字列になり、error.message は undefined になります。渡すのは必ず Error のオブジェクトにしてください
  • catch の中でさらに失敗する処理を書く — catch の中で落ちた例外を受け止める場所はありません。catch に書くのは、必ず成功する短い処理だけにします

JavaScript

catch (error) { return error.response.status; // response が無いと、ここでまた落ちる }

要件

  1. fetchWork(works, id) を作る。80 ミリ秒後に、id が一致する作品があれば resolve し、無ければ new Error("作品が見つかりません") で reject する
  2. loadWorkOrFallback(works, id) を async function として作り、fetchWork の await を try で囲む
  3. 成功したら { ok: true, message: タイトル + " を読み込みました" } を返す
  4. 失敗したら catch で受け止め、{ ok: false, message: error.message } を返す

入出力例

loadWorkOrFallback([{"id":1,"published":true,"title":"プロフィールサイト","views":120,"year":2026},{"id":2,"published":true,"title":"自己紹介カード","views":48,"year":2026},{"id":3,"published":true,"title":"スキル一覧の表","views":32,"year":2026},{"id":4,"published":true,"title":"作品ギャラリー","views":76,"year":2026},{"id":5,"published":false,"title":"学習ログ","views":0,"year":2025}], 1) → {"message":"プロフィールサイト を読み込みました","ok":true} loadWorkOrFallback([{"id":1,"published":true,"title":"プロフィールサイト","views":120,"year":2026},{"id":2,"published":true,"title":"自己紹介カード","views":48,"year":2026},{"id":3,"published":true,"title":"スキル一覧の表","views":32,"year":2026},{"id":4,"published":true,"title":"作品ギャラリー","views":76,"year":2026},{"id":5,"published":false,"title":"学習ログ","views":0,"year":2025}], 99) → {"message":"作品が見つかりません","ok":false} loadWorkOrFallback([], 1) → {"message":"作品が見つかりません","ok":false} loadWorkOrFallback([{"id":1,"published":true,"title":"プロフィールサイト","views":120,"year":2026},{"id":2,"published":true,"title":"自己紹介カード","views":48,"year":2026},{"id":3,"published":true,"title":"スキル一覧の表","views":32,"year":2026},{"id":4,"published":true,"title":"作品ギャラリー","views":76,"year":2026},{"id":5,"published":false,"title":"学習ログ","views":0,"year":2025}], 5) → {"message":"学習ログ を読み込みました","ok":true}

ヒント

new Promise に渡す関数は resolve と reject の 2 つを受け取ります。見つからないときだけ reject を呼んでください

reject に渡すのは文字列ではなく new Error(...) です。文字列を渡すと catch の中で error.message が undefined になります

catch を書き忘れると、この関数は例外を投げたまま終わります。採点ではその 1 件が不正解になります

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/06·更新 2026/08/26

関連レッスン

  • つくる 読み込み中の表示を出す

    300 ミリ秒遅れて届く Promise を自作し、待っているあいだのスピナーと、届いたあとのカード表示を切り替えます。第9章で通信につなぐ前の下ごしらえです。

  • 第1章まとめクイズ

    Promise の確定、await の書き忘れ、forEach の中の await、Promise.all の並び順、reject の受け止め方を、コードを読んで確かめます。

  • HTTP と REST の読みかた

    ブラウザとサーバーが 1 往復でやりとりする HTTP の形と、URL の付けかたをそろえる REST の考えかたを読み解きます。

  • ファイルを分けるという考えかた

    長くなった app.js を役割ごとのファイルに切り分ける仕組みを読みます。export と import の形と、この教材では走らせられない理由を扱います。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • Promise非同期の結果を表すラッパーオブジェクト
  • 非同期完了を待たずに次へ進み、後で結果を受ける
  • 同期処理が終わるまで次に進まない実行順
  • オブジェクトキーと値のペアで構造を作るデータ
  • 関数処理に名前を付けて再利用できる単位
  • 変数データに名前をつけて参照する仕組み
  • 処理計算や代入を表す長方形
main.js
学習モード
エディタを読み込んでいます

メモ

非同期のエラーを捕まえる

⌘S で保存