JavaScript | 「AsyncFunction(非同期関数)」の基本

JavaScript
スポンサーリンク

async / await と「AsyncFunction(非同期関数)」の基本を、プログラミング初心者向けにやさしく解説します。


1. まずはざっくり説明

  • AsyncFunction(非同期関数) は、JavaScript で「非同期処理(時間がかかる処理)をわかりやすく書くための仕組み」です。
  • async キーワードを関数に付けると、その関数は 常に Promise を返す関数 になります。
  • 関数の中で await を使うと、Promise の完了を待ってから次の行に進むように書けます。これにより「非同期コード」が同期コード(上から順に読める)のように書け、読みやすくなります。

2. 基本の書き方

通常の async 関数

async function fetchUser() {
  // ここは Promise を返す処理を待てる
  let res = await fetch('/api/user');
  let data = await res.json();
  return data; // 実際には Promise.resolve(data) が返される
}

// 呼び出し側
fetchUser().then(user => console.log(user));
JavaScript

無名関数(関数式 / アロー関数)

const f = async () => {
  return 42;
};

f().then(x => console.log(x)); // -> 42
JavaScript

ポイント

  • awaitPromise に対してのみ意味があるawait 42 は即座に 42 を返す(42Promise.resolve(42) のように扱う)。
  • async 関数はエラーが投げられると reject 状態の Promise を返す(例:throw new Error('oops'))。

3. なぜ便利か(同期風に書ける)

従来の Promise チェーンはネストや .then() が続いて読みにくくなることがあります:

fetch('/a')
  .then(r => r.json())
  .then(d => fetch('/b/' + d.id))
  .then(r2 => r2.json())
  .then(d2 => console.log(d2))
  .catch(err => console.error(err));
JavaScript

async/await を使うと:

async function main() {
  try {
    const r = await fetch('/a');
    const d = await r.json();
    const r2 = await fetch('/b/' + d.id);
    const d2 = await r2.json();
    console.log(d2);
  } catch (err) {
    console.error(err);
  }
}

main();
JavaScript

上から順に読むだけで流れが分かるので、バグを見つけやすくなります。


4. 返り値とエラー処理

  • async function f() { return 1; } を呼ぶと f()Promise を返し、最終的に解決値は 1 になります。
  • 関数内で throw すれば、呼び出し側では catchtry/catch または .catch())で扱います。
async function g() {
  throw new Error('fail');
}

g().catch(e => console.log('err', e.message));

// async 内での try/catch
async function h() {
  try {
    await someAsync();
  } catch (e) {
    console.error('失敗', e);
  }
}
JavaScript

5. 同時に複数の処理を実行したいとき

await は順番に待つので、並列に実行したいときは Promise.all を使います。例:

async function parallel() {
  // 並列に開始
  const p1 = fetch('/a');
  const p2 = fetch('/b');

  // 両方の完了を待つ
  const [r1, r2] = await Promise.all([p1, p2]);
  const d1 = await r1.json();
  const d2 = await r2.json();
  return [d1, d2];
}
JavaScript

もし await fetch('/a') を先に書くと /b はその間待たされ、全体が遅くなる。


6. イベントループと非同期の簡単なイメージ

  • await を使うとその関数の実行は一旦中断(次のマイクロタスクへ委ねられる)され、他の処理が動きます。重たい処理をブロックしないため、UI は反応し続けます。
  • 重要:await で待っている間に他の同期コード(同じスレッド上)をブロックしないように書くこと。

7. AsyncFunction コンストラクタ(上級テーマ)

Function と同様に、AsyncFunction コンストラクタを使って非同期関数を文字列から作ることもできます(通常は使わない):

const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
const af = new AsyncFunction('x', 'y', 'return await x + y');
// 生成された af は async 関数と同等。af(1,2).then(...)
JavaScript

ただし文字列から作る手法は可読性・セキュリティの面で避けるべきです。


8. よくある落とし穴とコツ

  • await をトップレベルで使うには(モジュールでないページだと)async 関数内に入れるか、または最新の環境でトップレベル await を使う(Node.js や ES Module 環境で許可される)必要があります。
  • await のつけ忘れ:const r = fetch(url);rPromise で、await fetch(url)Response
  • 並列実行したい場合は Promise.all を使う。複数 await を順に書くと逐次実行になる。

9. 実践的な例(ブラウザ向け)

ユーザー情報を非同期に取得して表示する簡単な例(エラーハンドリング付き):

<button id="btn">ユーザー取得</button>
<script>
  document.getElementById('btn').addEventListener('click', async () => {
    try {
      const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
      if (!res.ok) throw new Error('通信エラー');
      const user = await res.json();
      console.log('ユーザー名', user.name);
    } catch (e) {
      console.error('取得失敗', e);
    }
  });
</script>
HTML

10. 演習問題

  1. async を使って 1 秒待ってから "done" を返す関数 waitAndReturn を作れ(setTimeout を Promise 化して使う)。

解答例

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function waitAndReturn() {
  await sleep(1000);
  return 'done';
}

waitAndReturn().then(console.log); // 1 秒後に 'done'
JavaScript
  1. 3 つの URL を同時に取得して、それぞれの JSON をまとめて返す関数を async/awaitPromise.all で作れ。

11. まとめ

  • async/await(AsyncFunction)は、非同期処理を「読みやすく」書くための強力な道具。Promise の世界をシンプルに扱える。
  • await は Promise の完了を待つ。複数の処理を並列実行したいときは Promise.all を使う。
  • 例外処理は try/catch。トップレベルでの await は環境に注意。

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