BeaSkyblue

JavaScriptの非同期処理まとめ(Promiseとasync/await超入門メモ)

· 5 min read

JavaScript の非同期処理をサクッとおさらいしたメモです。コードサンプルはそのままコピペして試せます。


1. JavaScript の実行モデルざっくり

  • 基本は 上から順番に実行(同期処理)
  • ただし setTimeout / fetch / async 関数などの 非同期処理 は「あとで実行するタスク」としてキューに回される
  • 非同期の完了タイミングで イベントループ がキューのタスクを拾い、続きを実行する

2. Promise とは何か

  • 「将来手に入る値への箱」 のようなオブジェクト
  • 代表的に Promise を返すもの:
    • fetch(url)Promise<Response>
    • res.json()Promise<any>
    • async function foo() {} で宣言された関数
async function foo() {
  return 123;
}

const p = foo(); // p は Promise<number>

3. async / await の挙動

function wait(ms) {
  return new Promise((resolve) => {
    setTimeout(() => resolve("done"), ms);
  });
}

async function main() {
  console.log("A");
  const result = await wait(1000);
  console.log("B", result);
}

main();
console.log("C");

このときのログの順番は:

  1. A
  2. C
  3. B done

ポイント:

  • await に来たとき、その async 関数の中だけ一時停止 する
  • 呼び出し元のコード(ここでは console.log("C"))は 先に進む
  • Promise が解決されたタイミングで、止まっていた関数の続きが実行される

まとめると:

await = 「この Promise の結果が出るまで、この関数の続きを一旦止める」


4. fetch + res.json の典型パターン

async function loadUser() {
  console.log("start");

  const res = await fetch("/api/user"); // Response を待つ
  const data = await res.json(); // JSON パース完了を待つ

  console.log("user name:", data.name);
  console.log("end");
}

loadUser();
console.log("after loadUser");

ログの順番:

  1. start
  2. after loadUser
  3. user name: ...
  4. end

res.json に await を付けないとどうなるか?

const data = res.json(); // await なし
console.log(data.name); // ❌ data は Promise なので name は undefined
  • res.json()JSON オブジェクトではなく Promise を返す
  • await res.json() と書くことで、パース完了後の「中身のオブジェクト」 を受け取れる

5. await するとき / しないとき

基本ルール(アプリコード目線)

  • 今すぐ結果が欲しいときawait する

    const user = await getUser(id);
    
  • とりあえず「値が欲しいなら await」で OK

await しないパターン(少し進んだ使い方)

  1. 並列で実行して、あとでまとめて待つ

    const p1 = fetch("/a");
    const p2 = fetch("/b");
    
    const [resA, resB] = await Promise.all([p1, p2]);
    
  2. 呼び出し側に Promise を返したいとき

    async function getUser(id) {
      const res = await fetch(`/api/users/${id}`);
      return res.json(); // Promise をそのまま返す
    }
    
    const user = await getUser(1);
    
  3. 結果に依存しない「投げっぱなし」(ログ送信など)

    function trackEvent(name) {
      fetch("/track", {
        method: "POST",
        body: JSON.stringify({ name }),
      }); // await しない
    }
    

6. よくあるつまずきポイントまとめ

  • await を付け忘れると、値ではなく Promise のまま になる
  • await関数全体を止めるのではなく、その async 関数の中だけ止める
  • ログの順番がおかしく見えたら、次の2点をチェック
    • どこで await しているか
    • どこからどこまでが async 関数の中か

非同期処理は慣れるとシンプルです。await が止める範囲と Promise が返すタイミングを意識すれば読みやすくなります。