基礎から学ぶJavaScript入門 90日コース | 非同期処理とAPI - Day 58:async / await

JavaScript 90日で身につけるJavaScript
スポンサーリンク
スポンサーリンク

Day 58:async / await

Day 58では、第5フェーズ「非同期処理とAPI」の重要な書き方として、async と await を学びます。Day 57では Promise を学び、非同期処理の結果を「あとで受け取る約束」として扱う考え方を理解しました。そこでは、成功時に .then()、失敗時に .catch() を使う書き方を練習しました。Promise は非同期処理を整理するためにとても重要ですが、初心者の方にとっては、処理が何段も続くと少し読みづらく感じやすいことがあります。そこで登場するのが async / await です。

async / await は、Promise をより読みやすく、順番を追いやすい形で書くための仕組みです。完全に新しい別物というより、「Promise をわかりやすく書くための書き方」だと考えると理解しやすいです。つまり、Day 58 は Promise を捨てて新しいことを学ぶ回ではありません。むしろ、Day 57で学んだ Promise を土台として、その上に「もっと読みやすい書き方」を重ねる回です。

初心者の方にとって、この async / await はとても大切です。なぜなら、今後 fetch() を使ってAPI通信をするとき、現場でも学習教材でもよく出てくる書き方だからです。そして何より、コードの流れを人間が追いやすくなります。今回も、単に文法だけを覚えるのではなく、「なぜ便利なのか」「Promise とどう関係しているのか」「どこで使えるのか」を順番に整理しながら、例題やコード付きで丁寧に説明していきます。

まず最初に結論をつかむ

最初に今回の結論をシンプルに言うと、async / await は Promise を同期処理のように読みやすく書くための仕組みです。

もう少し具体的に言うと、

  • `async` は「この関数の中で非同期処理を扱います」と示すものです。
  • `await` は「Promise の結果が返ってくるまでここで待ちます」という意味です。

ただし、ここでいう「待つ」は、Day 56で学んだように、アプリ全体を止めるという意味ではありません。あくまで「その関数の中で結果を受け取るまで次に進まないように見せる」ための書き方です。初心者の方は、まずこの全体像をつかんでおくと、そのあとの細かい説明がつながりやすいです。

Promiseの書き方を振り返る

async / await を理解するには、まず Promise の書き方を少し振り返ることが大切です。たとえば、2秒後にデータを返す Promise は次のように書けました。

// Promise を返す関数
function getMessage() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("データを取得しました。");
    }, 2000);
  });
}

// Promise の結果を受け取る
getMessage()
  .then(function (result) {
    console.log(result);
  })
  .catch(function (error) {
    console.log(error);
  });
JavaScript

この書き方でも正しく動きます。しかし、処理が増えていくと .then() が何個も続いたり、入れ子のように感じたりして、初心者の方には少し流れを追いにくくなることがあります。そこで、より上から下へ自然に読めるようにしたのが async / await です。

asyncとは何か

async は、関数の前につけて使います。この async がついた関数は、「Promise を扱える関数」になります。特に重要なのは、この中で await を使えるようになることです。

書き方は次のようになります。

async function 関数名() {
  // 非同期処理を書く
}
JavaScript

たとえば、こうです。

// async 関数を定義する
async function showMessage() {
  console.log("メッセージを表示します。");
}
JavaScript

初心者の方は、async を「この関数では非同期処理の特別な書き方が使えます」という目印だと考えると理解しやすいです。

async関数の大事な性質

ここで重要なポイントがあります。async をつけた関数は、戻り値として Promise を返します。これが初心者の方には少し不思議に感じるところです。

たとえば、次のような関数があるとします。

async function getNumber() {
  return 10;
}
JavaScript

この関数は一見すると 10 を返しているように見えますが、実際には Promise として返します。つまり、内部的には「10 を成功結果として持つ Promise を返している」ような形になります。

初心者の段階では、「async をつけた関数は Promise を返す」とまず覚えておけば十分です。ここがわかると、await との関係も理解しやすくなります。

awaitとは何か

await は、Promise の結果が返ってくるまで待つために使います。ただし、await はどこでも使えるわけではなく、async 関数の中で使います。ここは非常に重要です。

書き方は次のようになります。

const 結果 = await Promiseを返す処理;
JavaScript

たとえば、先ほどの getMessage() を await で受け取るとこうなります。

async function showData() {
  const result = await getMessage();
  console.log(result);
}
JavaScript

このコードは、「getMessage() の結果が返ってくるまで待って、そのあと result に入れて表示する」という意味です。

初心者の方は、await を「Promise の結果を普通の値のように受け取るための書き方」と考えるとわかりやすいです。

Promiseを async / await で書き換える

ここがDay 58の中心です。Promise の .then() を使った書き方を、async / await に書き換えてみます。

まずは Promise の書き方です。

function getMessage() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("データを取得しました。");
    }, 2000);
  });
}

getMessage().then(function (result) {
  console.log(result);
});
JavaScript

これを async / await にすると、こうなります。

function getMessage() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("データを取得しました。");
    }, 2000);
  });
}

async function showData() {
  const result = await getMessage();
  console.log(result);
}

showData();
JavaScript

この書き方の良さは、上から下へ読むだけで流れがわかりやすいことです。初心者の方は、.then() のときよりも「先に結果を受け取ってから次に進む」ように見えるため、感覚的につかみやすいことが多いです。

なぜ async / await が読みやすいのか

ここはとても大切です。なぜ async / await が読みやすいのかというと、見た目が同期処理に近いからです。たとえば、次の2つを比べてみてください。

.then() を使う書き方

getMessage().then(function (result) {
  console.log(result);
});
JavaScript

async / await を使う書き方

const result = await getMessage();
console.log(result);
JavaScript

後者のほうが、「まず結果を受け取って、次に表示する」という順番がそのまま見えやすいです。初心者の方は、async / await を「非同期処理を同期っぽく読めるようにする書き方」と理解すると、とてもわかりやすくなります。

エラー処理はどうするのか

Day 57では、Promise の失敗時には .catch() を使いました。では、async / await ではどうするのでしょうか。ここで使うのが try...catch です。

たとえば、失敗する可能性がある Promise を考えます。

function getData() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      reject("データの取得に失敗しました。");
    }, 2000);
  });
}
JavaScript

これを async / await で安全に扱うには、次のように書きます。

async function showData() {
  try {
    // Promise の成功結果を待つ
    const result = await getData();
    console.log(result);
  } catch (error) {
    // Promise が失敗したときの処理
    console.log(error);
  }
}

showData();
JavaScript

初心者の方は、.catch() の代わりに try...catch を使うと覚えると整理しやすいです。

try…catch をかみ砕いて理解する

try...catch は、まず try の中の処理を実行し、もし途中でエラーが起きたら catch に移る仕組みです。async / await では、await した Promise が reject されると、その失敗が catch に入ります。

つまり、

  • 成功したら `try` の中をそのまま進む
  • 失敗したら `catch` の中で受け止める

という形です。初心者の方は、try...catch を「成功ルートと失敗ルートを分ける箱」と考えると理解しやすいです。

Promise と async / await の関係を整理する

ここで大切なのは、async / await は Promise を置き換えているのではなく、Promise を使いやすくしているだけだということです。Promise がなくなるわけではありません。むしろ、await が待っている相手は Promise です。

つまり関係を整理するとこうなります。

  • Promise は非同期処理の結果を表す仕組みです。
  • `async / await` は Promise を読みやすく扱うための書き方です。

初心者の方は、これを「中身は Promise、見た目をわかりやすくしたのが async / await」と覚えると非常にわかりやすいです。

よくあるつまずきポイント

Day 58で初心者の方がつまずきやすいポイントを整理しておきます。

  • `await` は `async` 関数の中でしか使えません。
  • `await` を使ったからといってアプリ全体が止まるわけではありません。
  • `async / await` を使っても、非同期処理であること自体は変わりません。
  • 失敗の可能性があるなら `try…catch` が必要です。

特に大切なのは、「見た目は同期っぽくても、中身は非同期処理のまま」という点です。ここを勘違いすると、次のAPI学習で混乱しやすくなります。

ステップバイステップで変換してみる

ここでは、Promise のコードを async / await へ変換する流れを順番に見てみます。

ステップ1:Promise を返す関数を用意する

function getMessage() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("メッセージを取得しました。");
    }, 2000);
  });
}
JavaScript

ステップ2:.then() で受け取る

getMessage().then(function (result) {
  console.log(result);
});
JavaScript

ステップ3:async 関数を作る

async function showMessage() {
}
JavaScript

ステップ4:await で結果を受け取る

async function showMessage() {
  const result = await getMessage();
  console.log(result);
}
JavaScript

ステップ5:関数を実行する

showMessage();
JavaScript

この流れで見ると、.then() の中に書いていた処理を、async 関数の中へ上から下に並べ直している感覚だとわかります。初心者の方は、この変換の流れを一度自分で手を動かして確認すると定着しやすいです。

そのまま試せるテンプレート

ここでは、Promise と async / await の両方を比べて試せるテンプレートを紹介します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Day 58 async / await</title>
</head>
<body>
  <h2>async / awaitの確認</h2>

  <button id="promiseButton">Promiseで実行</button>
  <button id="asyncButton">async / awaitで実行</button>

  <p id="message">ここに結果が表示されます。</p>

  <script>
    // 必要な要素を取得する
    const promiseButton = document.getElementById("promiseButton");
    const asyncButton = document.getElementById("asyncButton");
    const message = document.getElementById("message");

    // Promise を返す関数
    function getData() {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          // 2秒後に成功結果を返す
          resolve("データを取得しました。");
        }, 2000);
      });
    }

    // Promise の .then() を使う処理
    promiseButton.addEventListener("click", function () {
      message.textContent = "Promiseで処理中です...";

      getData()
        .then(function (result) {
          message.textContent = "Promise: " + result;
        })
        .catch(function (error) {
          message.textContent = "Promise: " + error;
        });
    });

    // async / await を使う処理
    async function showData() {
      try {
        // Promise の結果を待つ
        const result = await getData();

        // 結果を表示する
        message.textContent = "async / await: " + result;
      } catch (error) {
        // 失敗時の処理
        message.textContent = "async / await: " + error;
      }
    }

    // ボタンが押されたら async 関数を実行する
    asyncButton.addEventListener("click", function () {
      message.textContent = "async / awaitで処理中です...";
      showData();
    });
  </script>
</body>
</html>

このテンプレートでは、同じ非同期処理を Promise の .then() と async / await の両方で試せます。初心者の方は、どちらも結果は同じでも、async / await のほうが流れを追いやすいと感じられるはずです。

さらに理解を深める小さな例

async / await の良さは、処理が連続するとさらによく見えます。たとえば、1つ目の処理が終わってから2つ目の処理をしたいとき、.then() でも書けますが、async / await のほうが順番が見えやすいです。

function step1() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("1つ目の処理が終わりました。");
    }, 1000);
  });
}

function step2() {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("2つ目の処理が終わりました。");
    }, 1000);
  });
}

async function runSteps() {
  const result1 = await step1();
  console.log(result1);

  const result2 = await step2();
  console.log(result2);
}

runSteps();
JavaScript

初心者の方は、このコードを見ると「上から順に進んでいるように見える」と感じやすいです。これが async / await の大きな利点です。

情報セキュリティの観点でも重要な点

async / await 自体は書き方の問題ですが、今後API通信や外部サービス連携で多く使います。そのため、失敗時の処理をきちんと try...catch で受けることがとても大切です。通信失敗時に何も対策がないと、画面が止まったように見えたり、誤った状態のまま表示されたりすることがあります。初心者の方は、await を使うときは「成功時だけでなく失敗時も必ず考える」と習慣づけると、安全で堅実なコードにつながります。

初心者が特に注意したいポイント

Day 58では、次の点を特に意識すると理解が深まりやすいです。

  • `async` は関数につけて使います。
  • `await` は Promise の結果を待つために使います。
  • `await` は `async` 関数の中で使います。
  • `async / await` は Promise をより読みやすく書くための仕組みです。
  • 失敗の可能性がある処理では `try…catch` を使います。
  • 見た目が同期処理に近くても、中身は非同期処理のままです。

特に重要なのは、「Promise が土台であり、async / await はその書きやすい表現」だという点です。ここがつながると、第5フェーズの学習がかなり安定します。

Day 58のゴールを整理する

Day 58では、次のことができるようになっていれば十分です。

  • `async` の役割を説明できる
  • `await` の役割を説明できる
  • Promise の `.then()` を `async / await` に書き換えられる
  • `try…catch` を使って失敗時の処理を書ける
  • `async / await` が Promise を読みやすくする仕組みだと理解している

ここまでできれば、Day 58としてはとても順調です。Promise の基礎理解の上に、より実践的な書き方がしっかり積み上がっています。

まとめ

Day 58では、第5フェーズ「非同期処理とAPI」の重要な書き方として、async / await を学びました。async は非同期処理を扱う関数であることを示し、await は Promise の結果が返るまで待つために使います。これによって、これまで .then() で受け取っていた Promise の結果を、同期処理のように上から下へ自然に読める形で書けるようになります。ただし、中身が非同期処理であることは変わらないため、失敗時には try...catch を使って正しくエラー処理を行う必要があります。

特に大切なのは、async / await は Promise を置き換える新しい仕組みではなく、Promise をわかりやすく書くための表現だということです。この関係が理解できると、これから学ぶ fetch() やAPI通信のコードが非常に読みやすくなります。

次に進む前に、今回のテンプレートで Promise の .then() を使った版と async / await を使った版を見比べてみるのがおすすめです。そして、「同じ処理なのに、どこが読みやすくなったのか」を自分の言葉で説明できるようになると、Day 58の理解がかなり深まっています。

タイトルとURLをコピーしました