JavaScriptの非同期処理をレストランに例えて理解しよう!
JavaScriptの非同期処理とイベントループは初心者にとって理解が難しい概念です。この記事では、レストランという身近な例えを使って、JavaScriptの実行モデルをわかりやすく解説します。
🍽️ JavaScriptの実行モデルをレストランにたとえる
| 用語 | レストランの役割 | JavaScriptの役割 |
|---|---|---|
| メインスレッド | 席に座っているお客様(現在対応中) | 今実行中のタスク(関数や処理が走っている状態) |
| タスクキュー | 順番待ちのお客様(料理が来るのを待っている) | 非同期処理の結果待ち(setTimeoutやイベント) |
| イベントループ | シェフ(空いた席がないかを確認し料理を運ぶ) | メインスレッドが空いたかを確認し、次の処理を実行 |
📝 具体例:レストランでの流れ
💡 シチュエーション
-
お客様(メインスレッド)が席に座って食事中
- 他の客(非同期処理)は順番待ち(タスクキュー)
-
順番待ちのお客様(非同期処理)が「デザート(setTimeout)」を注文
- シェフ(イベントループ)は「3分後に出します」と仮予約
- デザートができても、テーブルが空いてないと出せない
-
食事中のお客様(メインスレッド)が長々と食事を続ける(ブロッキング処理)
- デザートが出来上がっても、席が空くまで運べない
-
やっと席が空いた(メインスレッドが解放された)
- シェフ(イベントループ)が**デザート(非同期タスク)**を運ぶ
📝 JavaScriptでの動きに置き換える
コード
console.log("Start");
setTimeout(() => {
console.log("Dessert served");
}, 3000); // 3秒後に実行予約
const startTime = new Date();
while (new Date() - startTime < 5000); // 5秒間の食事(ブロッキング)
console.log("Main course done");
実行結果
Start
Main course done
Dessert served
🍰 解釈
-
Startを出力
- 最初のお客様が席に座り、メインディッシュを食べ始めた。
-
setTimeoutで「3秒後にデザートを出す」とシェフが予約
- デザート注文がタスクキューに入るが、まだ運ばれない。
-
5秒間のブロッキング(食事中)
- お客様がメインディッシュを食べ続けているため、シェフがデザートを出すタイミングを逃す。
-
食事が終わり席が空いた(メインスレッドが解放)
- シェフが順番待ちのデザートをすぐに運ぶ。
🔍 イベントループの流れを図解
┌─────────────────────┐
│ メインスレッド │
│ (現在席に座っている人) │
└──────────┬──────────┘
│
│ 完了
▼
┌─────────────────────┐ ┌─────────────────────┐
│ イベントループ │ 次へ │ タスクキュー │
│ (席が空いたか確認) │◄─────┤ (デザート提供待ち) │
└──────────┬──────────┘ └─────────────────────┘
│
│ 空席確認
▼
┌─────────────────────────┐
│メインスレッドが空いている?│
└────────────┬────────────┘
│
┌─────────┴─────────┐
│ │
▼ ▼
【はい】席が空いた 【いいえ】まだ食事中
│ │
▼ │
次のタスクを実行 │
│ │
└────────────────────┘
🍽️ よりわかりやすくするポイント
「テーブルが空かないと料理が出せない」
- メインスレッドが空かないと、非同期処理が実行されない。
- デザートが出来ても、テーブルが塞がっていれば運べない。
「料理を運ぶのはシェフ」
- シェフ(イベントループ)は、メインスレッドが空いたかを確認して、空いたら次の料理を運ぶ。
- シェフ自体が料理を作るわけではなく、タイミング管理が仕事。
「非同期処理は予約しているだけ」
- デザートを頼んだからといって、すぐに出てくるわけではない。
- 予約が通っても、実際に提供されるのは席が空いてから。
💡 このたとえで覚えるポイント
- メインスレッド(席に座っているお客様)が食事をしている間は、他の料理が出せない。
- タスクキュー(順番待ちの料理)は、メインスレッドが空いたときに順番に提供される。
- イベントループ(シェフ)は、メインスレッドが空いたかを常に監視し、空いた瞬間に次のタスクを持ってくる。
- 非同期処理(デザートの予約)は、**後で実行するという「約束」**であり、予約が成立してもすぐには実行されない。
🚀 補足:もしメインスレッドが常に埋まっていたら?
- **ずっと席に座り続ける客(whileループでブロッキング)**がいると、予約していた料理が出せない。
- 結果として、デザートが溜まってしまい、提供が遅れる。
- 席が空いた瞬間にまとめて運ばれるが、注文タイミングが遅くなってしまう。
✅ まとめ
- メインスレッド=現在の仕事中のお客様:終わらない限り他の処理はできない
- タスクキュー=次に実行したい非同期処理の待機列:メインスレッドが空くのを待っている
- イベントループ=シェフ:メインスレッドが空いたときに次のタスクを実行
- 非同期処理=予約:実行タイミングが来ても、席が空いていないと実行できない
👨💻 実際に確認してみよう
以下のコードを実行して、実際の動きを確認してみましょう:
console.log("🍽️ お客様が入店しました");
// メインコースの注文
console.log("🍖 メインコースを注文しました");
// デザートを3秒後に予約
setTimeout(() => {
console.log("🍰 デザートが提供されました");
}, 3000);
// 5秒かかるメインコース(ブロッキング処理)
console.log("🕒 メインコースを食べています...");
const startTime = new Date();
while (new Date() - startTime < 5000);
console.log("✅ メインコースを食べ終わりました");
// 結果:
// 🍽️ お客様が入店しました
// 🍖 メインコースを注文しました
// 🕒 メインコースを食べています...
// ✅ メインコースを食べ終わりました
// 🍰 デザートが提供されました
この例では、3秒後にデザートを出す予約をしましたが、メインコースに5秒かかったため、デザートはメインコースが終わった後に提供されました。これがJavaScriptの非同期処理の基本的な流れです!
