JavaScript の実行モデル
シングルスレッドの特性(なぜ非同期処理が必要なのか)
JavaScript は シングルスレッド で動作するため、一度に一つの処理しか実行できません。
このため、長時間かかる処理(I/O、ネットワーク通信など)を同期処理で行うと、メインスレッドがブロックされ、他の処理が止まってしまいます。
そこで、非同期処理 を活用することで、他の処理を止めることなく並行して処理を進めることができます。
同期処理 vs 非同期処理(実行の仕組みと違い)
- 同期処理: 順番に処理が実行され、1つの処理が終わるまで次の処理は実行されない。
- 非同期処理: 時間がかかる処理を別の仕組みに委ね、結果が得られたら後で処理を再開する。
学習内容
実行モデルとは?
JavaScript のコードがどのように解釈・処理されるのかを決める仕組み。
メインスレッドとは?
JavaScript のコードを実行する中心的なスレッド。
ブラウザ環境では、以下のような処理をメインスレッドが管理します。
- ユーザー操作(クリック、キー入力など)
- 画面の描画
- 関数の呼び出し など
ポイント
- JavaScript は シングルスレッド で動作し、同期的な処理はメインスレッド上で実行される。
- ただし、メインスレッドが直接処理の流れを管理しているわけではない。
- 実際のタスクの順序やタイミングは イベントループ や タスクキュー によって制御される。
- イベントループ を通じて 「どの関数をいつ実行するか」 が決まり、メインスレッドが CPU に処理を依頼するイメージ。
イベントループとは?
タスクキューからルールに従ってコールスタックへ関数を追加する流れ
イベントループの流れ
- マクロタスクキュー からタスクを取り出し、コールスタック で実行
- マクロタスクが終了後、マイクロタスクキュー のすべてのタスクを実行
- 必要に応じて 描画更新
- 再度 マクロタスクを取り出し実行→ これを 繰り返す
イベントループ = 全体の処理の順番を取り仕切る現場監督
コールスタックとは?
同期処理の 実行順序を制御 するための スタック(LIFO) 構造。
コールスタックの仕組み
- 関数が 呼び出されると スタックに 積まれる。
- 関数の実行が 終わると スタックから 取り除かれる。
- 常にコールスタックのトップにある関数が実行される。
コールスタックの一番上 = メインスレッド
重要な特徴
- コールスタックが空になるまで他の処理は実行されない。
- 「作業員①」:同期処理を担当する作業員のような役割。
Web API とは?
ブラウザ(または Node.js などの実行環境)が提供する JavaScript 以外の機能 の総称。
例:
setTimeout
fetch
-
addEventListener
など
仕組み
- これらの API は ブラウザの内部で実装 されている。
-
setTimeout
やfetch
を呼び出すと、非同期処理としてブラウザに委ねられる。 - 処理が完了すると、タスクキューにコールバックを登録。
- イベントループがコールスタックに取り込み実行 → 非同期処理が可能に!
注意: Promise は Web API ではなく、JavaScript の機能。
タスクキュー(Task Queue) / コールバックキューとは?
非同期 API によって実行タイミングが予約された コールバック関数を蓄えておくキュー。
-
setTimeout
、setInterval
、DOM イベント
、XHR/Fetch
などによる非同期処理が完了すると、コールバック関数が マクロタスクキュー(タスクキュー) に登録される。 - イベントループは コールスタックが空になったタイミング で タスクキューの先頭のコールバックを実行。
「作業員②」:非同期処理のコールバックを管理する作業員
非同期処理とは?
JavaScript のメインスレッドが ブロックされるのを防ぐための処理方式。
仕組み
- 時間のかかる処理(I/O、ネットワーク通信など)を ブラウザや Node.js に委ねる。
- 処理が完了したタイミングで タスクキューに登録 し、イベントループを介して処理。
非同期な関数とは?
呼び出しと結果の取得が 同時ではなく、処理完了のタイミングで結果を返す関数。
例:
fetch
setTimeout
- DOM イベントハンドラ
- Node.js の I/O 関数 など
特徴
- メインスレッドがブロックされない。
- 非同期処理はブラウザや Node.js が担当し、処理完了後にコールバックをタスクキューへ。
ブラウザ環境でのイベントループの詳細な動作
-
マクロタスクの取り出し
- タスクキュー(マクロタスクキュー)の先頭のタスクを取り出し、コールスタックで実行。
-
setTimeout
や ユーザーイベント(クリックなど) のコールバックがここに入る。
-
コールスタックでの実行
-
fetch
やsetTimeout
の実際の処理はブラウザの内部へ(バックグラウンド処理)。 - 完了後に マクロタスクキュー or マイクロタスクキューに登録。
-
-
マイクロタスクの処理
- マクロタスクが終了後、マイクロタスクキューのタスクをすべて処理。
- 例:
Promise.then()
/catch()
/finally()
/await
の後処理。 - 優先度が高いため、すべて処理されるまで実行が続く。
-
ブラウザの描画更新
- 必要に応じて レンダリング(画面描画の更新) を実施。
-
次のマクロタスクへ
- マクロタスクキューの次のタスクを実行。
- タスクがない場合は待機。
マイクロタスクとマクロタスクの優先度
- マイクロタスク(Promise.then() など) → マクロタスクが終わった直後にすべて実行。
- マクロタスク(setTimeout など) → マイクロタスクが終わった後に次のループで実行。