さとまたwiki

非同期処理

時間のかかる処理を待たずにプログラムを実行する

非同期処理とは?なぜ必要?

日常での例え:レストランの注文

同期処理(悪い例)

1人の料理ができるまで
次の人の注文を取らない
→ 他のお客さんが待ちぼうけ

非同期処理(良い例)

注文だけ先に全員から取る
できた料理から順番に提供
→ 効率的!

Webページでの問題

API通信やファイル読み込みは時間がかかる:

  • 同期処理だと、通信が終わるまでページが固まる(フリーズ)
  • ボタンも押せない、スクロールもできない

非同期処理なら:通信中も他の操作ができる!完了したら結果を受け取る

コールバック関数

setTimeout

指定時間後に実行

javascript
console.log("開始");

setTimeout(() => {
  console.log("2秒後に実行");
}, 2000);

console.log("終了");

// 出力順:
// "開始"
// "終了"
// "2秒後に実行"  ← 2秒後
プレビュー
// 実行順序:
1. "開始"
2. "終了" ← すぐ実行
3. "2秒後に実行" ← 後から

Promise

「Promise(プロミス)」とは?

「約束」という意味。「結果は後で届けます」という約束のこと。
非同期処理の結果を「待つ」仕組みを提供します。

3つの状態
pending(保留中):まだ結果が出ていない
fulfilled(成功):処理が成功した → .then() で結果を受け取る
rejected(失敗):処理が失敗した → .catch() でエラーを処理

Promiseの基本

非同期処理の結果を表すオブジェクト

javascript
// Promiseの作成
const promise = new Promise((resolve, reject) => {
  // 非同期処理
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve("成功!");  // 成功時
    } else {
      reject("失敗...");  // 失敗時
    }
  }, 1000);
});

// 結果を受け取る
promise
  .then(result => console.log(result))  // "成功!"
  .catch(error => console.log(error));
プレビュー
Promise
├─ pending (保留中)
├─ fulfilled (成功) → .then()
└─ rejected (失敗) → .catch()

Promiseチェーン

連続した非同期処理

javascript
fetch("https://api.example.com/user")
  .then(response => response.json())  // レスポンスをJSONに
  .then(user => {
    console.log(user.name);
    return fetch("/api/posts?userId=" + user.id);
  })
  .then(response => response.json())  // 次のリクエスト
  .then(posts => console.log(posts))
  .catch(error => console.error(error));  // どこかでエラー
プレビュー
// .then() をつなげて順番に実行
// どこでエラーが起きても .catch() で捕まえる

async / await

async / await とは?

Promiseをもっと読みやすく書くための構文です。
.then() の連鎖より、普通のコードのように書けます。

async:「この関数は非同期処理をしますよ」と宣言
await:「この処理が終わるまで待って」と指定

基本的な使い方

Promiseをより直感的に書く

javascript
// async関数の定義
async function fetchUser() {
  // awaitでPromiseの完了を待つ
  const response = await fetch("https://api.example.com/user");
  const user = await response.json();
  return user;
}

// 呼び出し
const user = await fetchUser();
console.log(user.name);
プレビュー
async
関数が Promise を返すことを宣言
await
Promise の完了を待って結果を取得

エラーハンドリング

try-catchでエラーを捕捉

javascript
async function fetchData() {
  try {
    const response = await fetch("https://api.example.com/data");

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

    const data = await response.json();
    return data;

  } catch (error) {
    console.error("エラー発生:", error.message);
    throw error;  // 再スロー(呼び出し元に伝える)
  }
}
プレビュー
try
// 正常な処理
catch
// エラー時の処理

並列実行

Promise.allで複数を同時に

javascript
async function fetchAll() {
  // 並列で実行(速い!)
  const [users, posts, comments] = await Promise.all([
    fetch("/api/users").then(r => r.json()),
    fetch("/api/posts").then(r => r.json()),
    fetch("/api/comments").then(r => r.json())
  ]);

  return { users, posts, comments };
}

// Promise.allSettled: 全部の結果を取得(失敗も含む)
// Promise.race: 最初に完了したものを取得
プレビュー
Promise.all
// 全て成功 → 結果の配列
// 1つでも失敗 → 即エラー

fetch API

「fetch API」とは?

サーバーとHTTP通信するためのJavaScript標準機能。
データの取得(GET)、送信(POST)、更新(PUT/PATCH)、削除(DELETE)ができます。

「API」って何?

Application Programming Interfaceの略。
「サーバーとやり取りするための窓口」のこと。
例:天気APIに「東京の天気を教えて」とリクエスト → 天気情報が返ってくる

GETリクエスト

データの取得

javascript
// シンプルなGET
const response = await fetch("https://api.example.com/users");
const users = await response.json();

// クエリパラメータ付き
const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "javascript");
url.searchParams.set("limit", "10");

const result = await fetch(url);
プレビュー
GET /users
// → ユーザー一覧を取得

POSTリクエスト

データの送信

javascript
const response = await fetch("https://api.example.com/users", {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    name: "田中太郎",
    email: "tanaka@example.com"
  })
});

const newUser = await response.json();
プレビュー
POST /users
// → 新しいユーザーを作成

その他のメソッド

PUT, PATCH, DELETE

javascript
// PUT: 全体を置き換え
await fetch("/api/users/1", {
  method: "PUT",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "新しい名前", email: "new@example.com" })
});

// PATCH: 一部を更新
await fetch("/api/users/1", {
  method: "PATCH",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ name: "更新された名前" })
});

// DELETE: 削除
await fetch("/api/users/1", {
  method: "DELETE"
});
プレビュー
PUT - 全体を置き換え
PATCH - 一部を更新
DELETE - 削除

実践例

データ取得のパターン

エラーハンドリングとローディング

javascript
async function loadUsers() {
  const container = document.getElementById("users");
  container.innerHTML = "<p>読み込み中...</p>";

  try {
    const response = await fetch("/api/users");

    if (!response.ok) {
      throw new Error("データの取得に失敗しました");
    }

    const users = await response.json();

    container.innerHTML = users
      .map(user => "<div>" + user.name + "</div>")
      .join("");

  } catch (error) {
    container.innerHTML = "<p>エラー: " + error.message + "</p>";
  }
}

loadUsers();
プレビュー
// 1. ローディング表示
// 2. データ取得
// 3. 成功 → 表示 / 失敗 → エラー表示