Chapter 4: 非同期処理とAPI
Web アプリではサーバーからデータを取得したり,送信したりする場面が多く登場します。
この章では fetch と async/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));
ハンズオン:企画一覧を取得して表示
fes-training/javascript/apiフォルダを作り,index.html/main.js/styles.cssを用意。- 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>
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);
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 入門 に進み,型を利用した開発の流れを押さえましょう。