JavaScript | ゼロからはじめるプログラミング、30日で基礎を学ぶJavaScript:JavaScriptを使えるレベルにする - Day13.5:非同期処理

JavaScript JavaScript
スポンサーリンク

Day13.5 前半のゴール

非同期処理は「今すぐ終わらない処理」と仲良くするための仕組みです。
ネットワーク通信、ファイル読み込み、タイマーなどはすぐに終わらないので、
JavaScript は「待ちながらも他の処理を進める」必要があります。

前半のゴールはこの2つです。

Day13.5 前半でつかみたい感覚

Promise=「そのうち結果が返ってくる“約束”の箱」

async / await=「非同期処理を“ほぼ同期っぽく”書くための文法」


なぜ非同期処理が必要なのか

「終わるまで待ち続ける」と画面が固まる

もし、サーバーからデータを取ってくる処理を
「終わるまで完全に待つ」ようにしてしまうと、
その間、画面は一切反応しなくなります。

// こんな世界はあってはいけないイメージ
const data = fetchSync("https://example.com/data"); // 終わるまで完全に停止
console.log("ここに来るまで何もできない");
JavaScript

ブラウザは「ユーザーの操作にすぐ反応する」ことが大事なので、
JavaScript は「待っている間も他のことをする」=非同期で動きます。


Promise とは何か

「今はまだないけど、そのうち結果が入る箱」

Promise は、ざっくり言うとこういうものです。

「今は結果がないけど、
成功したら“成功の値”が、
失敗したら“エラー”が入る“約束の箱”」

実際のコードで見てみます。

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("成功しました");
  }, 1000);
});

console.log(promise);
JavaScript

この時点で promise の中には、
まだ「成功しました」という文字列は入っていません。
「1秒後に resolve が呼ばれる予定」という“約束”だけがある状態です。

then で「成功したときの処理」を登録する

Promise は、then を使って「成功したときにやること」を登録します。

promise.then((result) => {
  console.log("結果:", result);
});
JavaScript

ここでの流れはこうです。

Promise が作られる
1秒後に resolve(“成功しました”) が呼ばれる
→ then に渡した関数が呼ばれ、result に “成功しました” が入る

「終わったらこれをやってね」と予約しておくイメージです。


Promise の状態

3つの状態をざっくり理解する

Promise には、ざっくり3つの状態があります。

pending(保留中)
fulfilled(成功)
rejected(失敗)

さきほどの例では、

new Promise した直後 → pending
1秒後に resolve が呼ばれる → fulfilled

という流れになっています。

reject を呼ぶと rejected になります。

const p = new Promise((resolve, reject) => {
  reject(new Error("失敗しました"));
});

p.then((result) => {
  console.log("成功:", result);
}).catch((error) => {
  console.log("失敗:", error.message);
});
JavaScript

成功したら then、失敗したら catch が呼ばれます。
「成功と失敗を分けて書ける」のが Promise の大事なポイントです。


async / await とは何か

Promise を「同期っぽく」書くための糖衣構文

Promise は then / catch で書けますが、
複雑になってくると「then がネストして読みにくい」問題が出てきます。

そこで登場するのが async / await です。

async function main() {
  const result = await promise;
  console.log("結果:", result);
}

main();
JavaScript

ここで起きていることはこうです。

async を付けた関数の中でだけ await が使える
await promise と書くと、「promise の結果が来るまで一時停止」してくれる
結果が来たら、result に値が入り、次の行に進む

見た目は「同期処理」のように書けますが、
裏側ではちゃんと非同期で動いています。

async 関数は必ず Promise を返す

async を付けた関数は、
戻り値を自動的に Promise に包みます。

async function getValue() {
  return 42;
}

const p = getValue();
console.log(p); // Promise
JavaScript

p は Promise なので、then で受け取ることもできます。

getValue().then((v) => {
  console.log(v); // 42
});
JavaScript

「async 関数=Promise を返す関数」と覚えておくと、
頭の中が整理しやすくなります。


Promise と async / await を並べて見る

同じことを Promise だけで書く場合

function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("データ取得完了");
    }, 1000);
  });
}

fetchData().then((result) => {
  console.log(result);
});
JavaScript

同じことを async / await で書く場合

function fetchData() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("データ取得完了");
    }, 1000);
  });
}

async function main() {
  const result = await fetchData();
  console.log(result);
}

main();
JavaScript

やっていることは同じですが、
async / await のほうが「順番」が読みやすくなります。

  1. fetchData を呼ぶ
  2. 結果を result に入れる
  3. console.log する

という流れが、上から下に素直に読めます。


非同期処理とエラー(前半の触り)

await でもエラーは起きる

await している Promise が rejected になると、
その場で「例外」が投げられます。

function fetchWithError() {
  return new Promise((resolve, reject) => {
    reject(new Error("取得に失敗しました"));
  });
}

async function main() {
  const result = await fetchWithError(); // ここで例外
  console.log(result);
}

main();
JavaScript

このままだと、例外が処理されずにエラーになります。

try / catch と組み合わせる

前の Day13 で学んだ try / catch と組み合わせると、
非同期のエラーもきれいに扱えます。

async function main() {
  try {
    const result = await fetchWithError();
    console.log("成功:", result);
  } catch (error) {
    console.log("失敗:", error.message);
  }
}

main();
JavaScript

「await で待つ処理を try で囲う」
これが async / await 時代の基本パターンです。


Day13.5 前半のサンプルコード

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Day13.5 非同期処理 前半</title>
  </head>
  <body>
    <h1>Day13.5: 非同期処理(前半)</h1>

    <script>
      function fetchData() {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve("サーバーからのデータ");
          }, 1000);
        });
      }

      async function main() {
        console.log("取得開始");
        const data = await fetchData();
        console.log("取得結果:", data);
        console.log("処理終了");
      }

      main();
    </script>
  </body>
</html>

コンソールの出力順をよく見てください。
「取得開始」→ 1秒待つ → 「取得結果」→「処理終了」
という流れになっているはずです。


Day13.5 前半のまとめ

Promise は「そのうち結果が入る箱」。
async / await は「Promise を待つ処理を、同期っぽく書くための文法」。

前半では、

Promise の基本イメージ
then / catch の役割
async 関数と await の関係
await と try / catch の組み合わせの入り口

までを押さえました。

後半では、
複数の非同期処理を組み合わせる
エラー処理をしっかり設計する
セキュリティ的に「タイムアウト」「失敗時のふるまい」を考える

といった、より実務寄りの非同期処理に踏み込んでいきます。

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