コンテンツにスキップ

Chapter 4: 非同期処理とAPI

Web アプリではサーバーからデータを取得したり,送信したりする場面が多く登場します。
この章では fetchasync/await を使って非同期処理の基本を学びます。


非同期処理とは

JavaScript は 1 つのスレッドで動作します。時間のかかる処理(ネットワーク通信など)を待ってしまうと,ユーザー操作が止まってしまうため,「完了したら続きの処理を行う」仕組みが必要です。これが非同期処理です。


fetch の基本形

fetch("https://jsonplaceholder.typicode.com/posts/1")
  .then((response) => response.json())
  .then((data) => {
    console.log("取得したデータ", data);
  })
  .catch((error) => {
    console.error("エラーが発生しました", error);
  });

fetch は Promise を返します。.then で結果を受け取り,.catch でエラーを扱います。


async/await を使う

async/await を使うと,非同期処理を同期処理のように書けます。

async function fetchEvent(id) {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${id}`,
  );
  if (!response.ok) {
    throw new Error("ネットワークエラー");
  }
  return response.json();
}

fetchEvent(1)
  .then((event) => console.log(event))
  .catch((error) => console.error(error));

ハンズオン:企画一覧を取得して表示

  1. fes-training/javascript/api フォルダを作り,index.html / main.js / styles.css を用意。
  2. HTML を作成。
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>企画一覧</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <main class="container">
      <h1>企画一覧</h1>
      <button id="load">データを読み込む</button>
      <div id="status" role="status" aria-live="polite">準備中...</div>
      <div id="events" class="grid"></div>
    </main>
    <script type="module" src="main.js"></script>
  </body>
</html>
  1. main.js を実装。
const loadButton = document.getElementById("load");
const status = document.getElementById("status");
const eventsContainer = document.getElementById("events");

async function fetchEvents() {
  status.textContent = "読み込み中...";
  loadButton.disabled = true;

  try {
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/posts?_limit=6",
    );
    if (!response.ok) {
      throw new Error(`エラー: ${response.status}`);
    }

    const events = await response.json();
    renderEvents(events);
    status.textContent = `${events.length}件の企画を取得しました。`;
  } catch (error) {
    console.error(error);
    status.textContent = "データの取得に失敗しました。";
  } finally {
    loadButton.disabled = false;
  }
}

function renderEvents(events) {
  eventsContainer.innerHTML = "";
  events.forEach((event) => {
    const card = document.createElement("article");
    card.className = "card";
    card.innerHTML = `
      <h2>${event.title}</h2>
      <p>${event.body}</p>
    `;
    eventsContainer.appendChild(card);
  });
}

loadButton.addEventListener("click", fetchEvents);
  1. styles.css を追加。
body {
  font-family: "Segoe UI", "Hiragino Sans", sans-serif;
  background: #f8fafc;
  color: #1f2937;
  margin: 0;
}

.container {
  max-width: 960px;
  margin: 0 auto;
  padding: 40px 16px 64px;
}

button {
  background: #2563eb;
  color: #fff;
  border: none;
  padding: 12px 20px;
  border-radius: 999px;
  font-weight: 600;
  cursor: pointer;
}

button:disabled {
  background: #93c5fd;
  cursor: not-allowed;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
  margin-top: 24px;
}

.card {
  background: #fff;
  padding: 20px;
  border-radius: 16px;
  box-shadow: 0 16px 32px rgba(15, 23, 42, 0.12);
}

ボタンを押すと API からデータを取得し,カードとして表示されます。


エラー処理のポイント

  • response.ok で HTTP ステータスを確認する。
  • try / catch / finally で例外を扱う。
  • ユーザーに状況を伝えるメッセージを用意する。

練習課題

  • 取得したデータにタグ(例:#音楽)を付け,タグでフィルタリングできるようにしてみましょう。
  • 取得中はローディングアイコン(CSS アニメーションで OK)を表示し,完了したら非表示にしてみましょう。
  • 自分で JSON ファイルを用意し,fetch("./data/events.json") で読み込むローカル表示を作ってみましょう。

次へ進む

データ取得ができるようになったら,Chapter 5: TypeScript 入門 に進み,型を利用した開発の流れを押さえましょう。