実践JavaScript
同期と非同期
このレッスンで分かること
- 同期処理 ─ 上から順に実行、前の処理が終わるまで次に進まない
- 非同期処理 ─ 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);
// ネストが深くなっていく...
});
});
});イベントループ
イベントループは非同期処理を管理する仕組みです。
- コールスタックは同期処理を実行
- Web APIは非同期処理(setTimeout等)を処理
- コールバックキューは完了した非同期処理のコールバックを待機
- イベントループはコールスタックが空になったら、キューからコールバックを取り出して実行
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(...)だけ書いて結果が来る前に次の行へ行くバグ forEachでawait─for-ofかPromise.all(items.map(...))を使う- 例外の握りつぶし ─ async 関数の例外は
.catchかtry-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 つができることを確認しましょう。
- 同期と非同期 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 同期と非同期 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン