1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Promise / async-await / Generatorの違いと使い分け:JavaScript非同期設計のための構文戦略

Posted at

概要

JavaScriptにおける非同期処理には、以下の3つの主要な構文スタイルが存在する:

  • Promise: 非同期処理の構造化
  • async/await: 同期風の記述で非同期処理を簡潔に
  • Generator: 処理の“中断と再開”を可能にするイテレーター

それぞれが持つ特性と設計思想は異なり、
「どの構文を使うか」は単なる好みではなく、制御フローの設計選択そのものである。


対象環境

JavaScript(ES6〜ES2023)  
Node.js / モダンブラウザ両対応

1. Promise:非同期処理の構造化と連結

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve('data'), 1000);
  });
}

fetchData()
  .then(result => console.log(result))
  .catch(err => console.error(err));

✅ 特徴

  • then() / catch() / finally() によるチェーン処理
  • 並列実行 (Promise.all) に強い
  • 可読性は低くなりがち(ネストで複雑化)

2. async/await:同期処理のように非同期を書く

async function load() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (e) {
    console.error(e);
  }
}

✅ 特徴

  • ✅ 見た目が同期的 → 可読性が高い
  • ✅ エラーハンドリングも try/catch で統一
  • ❌ 並列処理は await の順番に依存する → Promise.all()との併用が必要

並列実行したい場合

const [a, b] = await Promise.all([fetchA(), fetchB()]);

3. Generator(+ coライブラリなど)

function* task() {
  yield new Promise(resolve => setTimeout(() => resolve('step1'), 500));
  yield new Promise(resolve => setTimeout(() => resolve('step2'), 500));
}
  • yield によって処理を一時停止できる
  • for...ofnext() により段階的に処理を進行
  • 単体では非同期制御は難しく、coredux-saga などの中間層と併用

async generator + for await...of

async function* steps() {
  yield await fetch('...');
  yield await fetch('...');
}

for await (const res of steps()) {
  console.log(await res.json());
}

構文・設計の違いまとめ

項目 Promise async/await Generator
見た目の構造 チェーン構造 同期的構造 明示的なステップ制御
非同期サポート ✅(awaitで内部的にPromise) ❌(明示的にPromiseをyield)
並列処理の簡便性 ⚠️ 要 Promise.all() ❌ やや難解
制御の細かさ 中程度 シンプル 高い(中断・再開)
ライブラリ併用の必要性 なし なし 必要(co / redux-saga)

実務での設計判断フロー

① 非同期処理が1回だけ? → async/await

② エラーをtry/catchで管理したい? → async/await

③ 複数Promiseを並列に処理したい? → Promise.all + async/await

④ 制御フローを段階的に記述したい? → Generator + ライブラリ

⑤ 同期・非同期の“混在”処理? → Generatorが最適

よくあるミス

❌ async関数は Promise を返すことを忘れる

async function example() {
  return 42;
}
example().then(v => console.log(v)); // 42(Promiseで返ってくる)

❌ await の使いすぎによる逐次化

// ❌ 順番に実行されて非効率
const a = await fetchA();
const b = await fetchB();

// ✅ 並列化
const [a, b] = await Promise.all([fetchA(), fetchB()]);

結語

非同期制御構文は、ただの書き方ではない。
制御の明確さ、エラー処理の一貫性、並列性、再利用性――
それらを設計としてどう選び、組み立てるかが問われている。

  • Promise は構造化の基盤
  • async/await は可読性の王者
  • Generator は制御性の鬼神

構文を知るだけでは設計にはならない。
“選ぶ理由”を理解し、“捨てる理由”を持てることが、設計者の第一歩である。

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?