【JavaScript入門】asyncとawait

 async / await は ES2017 で導入された “Promise を同期処理のように書く” シンタックスシュガーです。長い .then() チェーンをフラットに書き直し、可読性例外処理の一貫性 を大幅に高めます。ここでは構文の概要と使いどころを表・実践コードで整理し、最後に try … catch によるエラー制御も確認します。

1.async / await の基礎

概念説明
async 関数頭に async を付けた関数。戻り値は暗黙に Promise になる。
awaitPromise が 解決 (fulfilled) されるまで次の行へ進まない(直列化)
エラー伝播awaitreject()throw が起きると 例外 が発生し、try … catch で捕捉できる。

1.1. async が付くと何が変わるか

  • 明示的に Promise を返さなくても 自動で Promise 化
  • 関数外では func().then()await func() で結果を取得

1.2. await の動作

  • 右辺が Promise なら解決値を取り出す。
  • 右辺が値(非 Promise)なら即時にその値を返す。
  • awaitasync 関数内でのみ有効

1.3. エラー処理の統一

 Promise チェーンの .catch() と同じ役目を try … catch に集約できるため、同期コードと同じスタイルで書ける。

2.基本サンプル

ファイル名:async-await-demo.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>⚡️ async / await デモ</title>
  <style>
    body {font-family: "Segoe UI", sans-serif; margin: 2rem; background: #f0f8ff;}
    h1 {font-size: 1.8rem; text-align: center; margin-bottom: 1rem;}
    #log {white-space: pre-line; border: 1px solid #ccc; border-radius: 8px;
          padding: 1rem; background: #fff; min-height: 8rem;}
    button {padding: .6rem 1.2rem; border: none; border-radius: 6px;
            background: #0078d7; color: #fff; font-weight: bold; cursor: pointer;}
    button:hover {opacity: .85;}
  </style>
</head>
<body>
  <h1>⚡️ async / await デモ</h1>
  <button id="runBtn">非同期タスク開始</button>
  <div id="log"></div>

  <script>
  // 指定ミリ秒後に解決 / 拒否する Promise
  const waitTask = (label, ok = true, ms = 150) =>
    new Promise((resolve, reject) =>
      setTimeout(() => ok ? resolve(`${label} 完了`) : reject(`${label} 失敗`), ms)
    );

  const log = txt => document.getElementById("log").textContent += txt + "\n";

  // async 関数
  async function runFlow() {
    log("=== フロー開始 ===");
    log(await waitTask("タスクA"));          // 直列に実行
    log(await waitTask("タスクB"));
    log("--- 中間地点 ---");
    const c = await waitTask("タスクC");
    const d = await waitTask("タスクD");
    log(c);
    log(d);
    log("=== フロー終了 ===");
  }

  document.getElementById("runBtn").onclick = () => {
    document.getElementById("log").textContent = ""; // ログクリア
    runFlow().catch(e => log("予期せぬエラー: " + e));
  };
  </script>
</body>
</html>

ブラウザの出力例

プログラム解説

  1. waitTask はテスト用の非同期関数。ok=false にすると reject() を呼ぶ。
  2. await で直列化 — Promise が解決するまで次の行に進まないため、上から下へ順序どおりにログが出る。
  3. 関数外 (onclick 部分) では runFlow() が Promise を返すので .catch() で安全に例外を拾える。

3.try … catchawait

3.1. エラーを握りつぶさず取得する

ファイル名: async-await-try-catch.html

<!-- async-await-try-catch.html (抜粋) -->
<script>
async function runWithError() {
  log("▼ エラー実験 ▼");
  try {
    log(await waitTask("ステップ1"));
    log(await waitTask("ステップ2", false));   // ← ここで reject
    log(await waitTask("ステップ3"));          // 実行されない
  } catch (e) {
    log("例外捕捉: " + e);                    // reject がここへ飛ぶ
  } finally {
    log("▲ エラー実験終了 ▲");
  }
}
</script>

ブラウザの出力例

プログラム解説

 await に失敗すると同期コードの throw と同じように catch 節へジャンプします。UI のローディング解除は finally に書くと安心です。

4.ベストプラクティス

  • ループ + 並列処理 が欲しい場合は await をループ外に出し Promise.all() を組み合わせる。
  • 共通エラーハンドリング は関数の外で .catch()、局所的なハンドリングは try … catch
  • トップレベルの await はモジュール (<script type="module">) か (async () => {/*…*/})() で利用。

まとめ

 async / await により、複雑だった Promise チェーンを 同期的な読みやすさ で書けるようになります。await を使えば変数代入や try … catch に馴染みのある制御フローが戻ってきます。まずは小さな非同期関数を async に書き換え、処理の追いやすさ・バグの検出しやすさを体感してみましょう。