実践JavaScript

同期と非同期

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

このレッスンで分かること

  • 同期処理 ─ 上から順に実行、前の処理が終わるまで次に進まない
  • 非同期処理 ─ I/O やタイマー待ちの間に別の処理を進める (fetch / setTimeout)
  • JavaScript はシングルスレッド、Event Loop が非同期タスクを順に処理
  • Callback → Promise → async/await と進化、現代は async/await が主流

同期と非同期 とは

同期処理と非同期処理の違い、コールバックの仕組みを理解しよう。本レッスンでは、同期と非同期 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

同期と非同期

JavaScriptの非同期処理は、Webアプリケーション開発で最も重要な概念の一つです。

同期処理と非同期処理

同期処理は上から順番に実行されます。前の処理が終わるまで次に進みません。

JavaScript

// 同期処理:順番に実行 console.log("1. 開始"); console.log("2. 処理中"); console.log("3. 完了"); // 必ず 1 → 2 → 3 の順

非同期処理は、時間のかかる処理を待たずに次の処理に進みます。

JavaScript

console.log("1. 開始"); setTimeout(() => { console.log("2. 2秒後に実行"); }, 2000); console.log("3. すぐ実行"); // 出力順: 1 → 3 → 2(2は2秒後)

なぜ非同期が必要か

JavaScriptはシングルスレッドです。1つの処理しか同時にできません。

もし通信に3秒かかるとしたら、同期処理では3秒間画面が固まります。非同期処理なら、通信中も画面は動き続けます。

プレーンテキスト

【同期】 ────────通信(3秒)────────→ 次の処理 ↑ この間、画面が固まる 【非同期】 通信開始 → 次の処理 → ... → 通信完了! ↑ すぐ次に進む ↑ 結果を処理

コールスタック

JavaScriptはコールスタックで実行中の関数を管理します。

JavaScript

function first() { console.log("first"); second(); } function second() { console.log("second"); third(); } function third() { console.log("third"); } first(); // コールスタックの変化: // [] → [first] → [first, second] → [first, second, third] // → [first, second] → [first] → []

コールバック関数

非同期処理の最も基本的なパターンがコールバック関数です。

JavaScript

// setTimeoutのコールバック setTimeout(() => { console.log("1秒後"); }, 1000); // イベントリスナーのコールバック button.addEventListener("click", () => { console.log("クリックされた"); }); // コールバック地獄(こうなるとつらい) getData((data) => { processData(data, (result) => { saveData(result, (response) => { console.log(response); // ネストが深くなっていく... }); }); });

イベントループ

イベントループは非同期処理を管理する仕組みです。

  1. コールスタックは同期処理を実行
  2. Web APIは非同期処理(setTimeout等)を処理
  3. コールバックキューは完了した非同期処理のコールバックを待機
  4. イベントループはコールスタックが空になったら、キューからコールバックを取り出して実行

JavaScript

console.log("A"); setTimeout(() => console.log("B"), 0); console.log("C"); // 出力: A → C → B // ※ setTimeout(fn, 0)でも、コールスタックが空になるまで待つ

実務で遭遇するパターン

中級レッスンで学んだことが、実際の業務コードでどう登場するかを整理します。

  • API 呼び出しawait fetch(...) でレスポンスを待つ、UI はその間動き続ける
  • ファイル I/O ─ Node の fs.promises.readFile
  • タイマーsetTimeout / setInterval でディレイ実行
  • ユーザー操作待ち ─ クリックや入力イベントは非同期に発火

コードレビューで指摘されがちなポイント

PR を出すとシニアから入りやすい指摘です。先回りで身につけておけばレビューが一発で通ります。

  • async/await を使わずコールバック地獄 ─ ネストが 3 段超えたら async/await へ書き換え
  • Promise を await し忘れfetch(...) だけ書いて結果が来る前に次の行へ行くバグ
  • forEachawaitfor-ofPromise.all(items.map(...)) を使う
  • 例外の握りつぶし ─ async 関数の例外は .catchtry-catch で必ず処理

パフォーマンス考慮事項

  • 並列実行Promise.all([f1(), f2()]) で同時発射、await f1(); await f2() より速い
  • async 関数のオーバーヘッド ─ Promise を 1 回包む程度、無視できるレベル
  • Event Loop のブロック ─ CPU 重い同期処理は他のタスクを止める、setTimeout(..., 0) で分割
  • Worker Threads ─ CPU 並列が欲しい場合は Node Worker か Web Worker を使う
この章のポイント

ここまでの要点 JS はシングルスレッド + Event Loop、非同期は async/await で書く。並列は Promise.all、ループ内 await は for-of

まとめ

  • 同期処理は順番に実行、前の処理を待つ
  • 非同期処理は待たずに次へ進む、完了後にコールバックで処理
  • コールバック地獄はネストが深くなる問題 → Promise/async-awaitで解決
  • イベントループはコールスタック・キュー・Web APIの連携で非同期を実現

よくある質問

Q. 実務ではどんな場面でこの知識を使いますか?

A. API クライアントの実装、フロントエンドのフレームワーク内ロジック、Node.js のサーバーサイドなど幅広く登場します。React/Vue などのフレームワークもこの基礎の上に成り立っているため、ここで身につけた知識は資産になります。

Q. コードレビューで指摘されやすいポイントは?

A. var の使用、== の使用、無駄なネストの深さ、命名の曖昧さなどが頻出指摘です。Linter(ESLint)と Prettier を導入すれば機械的に防げる指摘が多いため、まずはツールで自動化するのが効率的です。

Q. 次に学ぶべき内容は何ですか?

A. Promise・async/await が理解できたら、fetch を使った API 連携、Web フレームワーク(React/Vue/SvelteKit)、ビルドツール(Vite/Webpack)に進むのがおすすめです。実プロジェクトでアウトプットしながら学ぶと定着が早まります。

次のレッスン

次は Promiseの基本 で、同期処理と非同期処理の違い、コールバックの仕組みを理解しよう を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. 同期と非同期 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. 同期と非同期 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン