JavaScript アドバンス

JavaScript Fetch API

1. Fetch API とは

fetch() は、サーバーからデータをリクエストするためのモダンな手法です。

  • fetch() は非同期(Asynchronous)であり、プロミス(Promise)を返します。
  • モダンなアプリケーションでは、データの取得に非同期コードを使用するのが一般的です。
  • fetch() は、その最も代表的な例と言えるでしょう。

2. fetch はプロミスを返す

fetch() は、呼び出し直後にデータそのものを返すわけではありません。
後でレスポンス(Response)を解決するためのプロミスを返します。

fetch("data.json")
.then(function(response) {
  console.log(response);
});

この結果として得られるのは Response オブジェクトであり、JSON データそのものではありません。

3. JSON データの取得

JSON データを取得するには、レスポンスのボディ(Body)を読み取る必要があります。
response.json() メソッドを実行すると、これ自体もまたプロミスを返します。

fetch("data.json")
.then(function(response) {
  // レスポンスを JSON として解析し、次のプロミスを返します
  return response.json();
})
.then(function(data) {
  // 解析されたデータにアクセスできます
  console.log(data);
});

これはプロミスチェーン(Promise chain)と呼ばれる構造です。

4. fetch と async / await

asyncawait を使用すると、fetch のコードをより直感的で読みやすく書くことができます。
これは特に初心者の方に推奨される、モダンな記述スタイルです。

async function loadData() {
  let response = await fetch("data.json");
  let data = await response.json();
  console.log(data);
}

loadData();

5. 重要:HTTP エラーの扱い

初心者がよく陥るミスに、「404(Not Found)や 500(Internal Server Error)が発生したときに fetch が失敗(Reject)する」と思い込んでしまうことがあります。
実際には、fetch がプロミスを拒否(Reject)するのはネットワークエラー(物理的な通信断絶など)の場合のみです。

404 レスポンスが返ってきても、プロミスは拒否されません。
そのため、必ず response.ok プロパティを確認する必要があります。

async function loadData() {
  let response = await fetch("missing.json");

  // HTTP ステータスが 200-299 以外の場合は対処が必要
  if (!response.ok) {
    console.log("HTTP エラーが発生しました:", response.status);
    return;
  }

  let data = await response.json();
  console.log(data);
}

loadData();

上記のように記述することで、HTTP エラーを正しくハンドリングできます。

6. ネットワークエラー

ネットワークエラーは、オフライン時や DNS エラーなど、リクエスト自体を完了できない場合に発生します。
この場合に限り、fetch のプロミスは拒否(Reject)されます。

async function loadData() {
  try {
    let response = await fetch("data.json");
    let data = await response.json();
    console.log(data);
  } catch (error) {
    // ネットワーク障害などはここでキャッチします
    console.log("ネットワークエラーが発生しました");
  }
}

7. fetch のよくあるミス

await を忘れると、データではなくプロミスそのものを操作しようとしてしまいます。

間違った例

async function loadData() {
  let response = await fetch("data.json");
  let data = response.json(); // await がない!
  console.log(data); // プロミスオブジェクトがログ出力されてしまいます
}

JSON を取得するには、必ず await を使用してください。

正しい例

async function loadData() {
  let response = await fetch("data.json");
  let data = await response.json();
  console.log(data);
}

8. デバッグのヒント

もし fetch がうまく動かない場合は、以下のステップでデバッグを行いましょう。

  1. コンソール(Console)を確認し、JavaScript のエラーが出ていないか見る。
  2. 次にブラウザの Network タブを確認する。
  3. ファイルパス(URL)は正しいか。
  4. ステータスコードは 200 か。
  5. レスポンスの中身は本当に正しい JSON 形式か。

実のところ、fetch の不具合の多くは JavaScript 自体のバグではなく、パスの設定ミスやサーバー側のレスポンスの問題です。

9. コールバック vs Fetch

ここでは、古い手法(コールバック)と新しい手法(Fetch)を比較してみましょう。

コールバックを使用した data.json の読み込み

function loadFile(callback) {
  let xhr = new XMLHttpRequest();
  xhr.open("GET", "data.json", true);
  xhr.onload = function() {
    if (xhr.status === 200) {
      callback(null, JSON.parse(xhr.responseText));
    } else {
      callback("HTTP エラー: " + xhr.status, null);
    }
  };
  xhr.onerror = function() {
    callback("ネットワークエラー", null);
  };
  xhr.send();
}

loadFile(function(error, data) {
  if (error) {
    console.log(error);
    return;
  }
  console.log(data);
});

10. コールバック手法の解説

  • loadFile() 自体はデータを返しません。
  • 処理結果を受け取るためのコールバック関数を引数に渡す必要があります。
  • ファイルが読み込まれた「後」にコールバックが実行されます。
  • エラー処理を手動で細かく記述する必要があります。
  • 処理ステップが増えるたびに、ネスト(入れ子)が深くなっていきます。

11. Fetch を使用したデータ読み込み

同じ処理を fetch で記述すると、非常にスッキリします。

async function loadFile() {
  try {
    let response = await fetch("data.json");

    if (!response.ok) {
      throw new Error("HTTP エラー: " + response.status);
    }

    let data = await response.json();
    console.log(data);
  } catch (error) {
    console.log(error);
  }
}

loadFile();

12. Fetch 手法の解説

  • fetch() はプロミスを返します。
  • await を使うことで、非同期処理を待機している間、関数の実行を一時停止できます。
  • エラーは try...catch で一括管理できます。
  • コードのフローが上から下へ流れるため、読みやすさが格段に向上します。
  • コールバックのネストから解放されます。

13. 主な違いのまとめ

特徴コールバック(XMLHttpRequest)Promise / async-await(Fetch)
基本的な考え方後で実行する関数を渡すプロミスの解決を待機する
エラー処理手動のエラー優先パターンが必要try...catch による組み込みフロー
可読性ネストが深くなりやすい通常の同期コードのように読める
チェーン処理困難メソッドチェーンで容易に記述可能