#コールスタック
- 実行中のコードがたどってきたコンテキストの積み重ね。
- スタックの仕組みを「後入れ先出し」という。
- 英語:LIFO(Last In, First out)
case
function a() {
}
function b() {
a();
}
function c() {
b();
}
c();
上記のケースでどのようにコンテキストが生成され積み重なるのか見てみる。
- コールスタック(コンテキストの積み重ね。)
- a関数コンテキスト =>実行中コンテキスト
- b関数コンテキスト
- c関数コンテキスト
- グローバルコンテキスト(関数が呼ばれるまえに生成される。)
- ※一番上に積み重ねられているのが実行中のコンテキストになる。
- 実行されたものからcall Stackからなくなっていく。
- 今回のケースはa()関数が最後に入り、最初に出ていくことになる。
- すなわち「後入れ先出し」。
※画面右下のCall Stackに注目。
タスクキュー
- 実行待ちの非同期処理の行列。
- 以下のようなキューの仕組みを「先入れ先出し」という。
- 英語:FIFO(First In, First Out)
- キューに入ってきたものから処理を進めていく。
タスクE
↓
タスクをキューの中で非同期処理の実行順を管理している。
ーーーーーーーー
| キュー |
| タスクD |
| タスクC |
| タスクB |
ーーーーーーーー
↓
タスクA
case
const btn = document.querySelector('button');
btn.addEventListener('click', function task2() {
console.log('task2 done');
});
function a() {
setTimeout(function task1() {
console.log('task1 done');
}, 4000);
const startTime = new Date();
while (new Date() - startTime < 5000);
console.log('fn a done');
}
a();
上記のコードの説明
- a関数を実行
- するとwhile文がメインスレッドを5秒間占有する。
while (new Date() - startTime < 5000);
- その間にクリックイベントを発火させる。
btn.addEventListener('click', function task2() {
console.log('task2 done');
- 5秒後にa関数の
fn a done
が表示され - クリックイベントの
task2 done
が表示され - 最後にa関数内のsetTimeoutの
task1 done
が表示される仕組みになっている。
タスクキューとコールスタックの関係はどうなっているのか?
※テキストで読みずらいいと思います。時間がある時に図解にします。
- 登場人物
- コールスタック
- タスクキュー
- イベントループ
- イベントループはコールスタックにコンテキストが積まれているかを監視をして、タスクキューに伝えている。
- コールスタック
- グローバルコンテキストが設置される。
- グローバルコンテキストにはのちに実行される非同期処理のクリックイベント(task2)が準備されている。
- その後a関数がコンテキストに追加され5秒間メインスレッドを占有する。
- a関数にはのちに実行される非同期処理のsetTimeout(task1 done)が準備されている。
- グローバルコンテキストが設置される。
- イベントループはこの時、「コールスタックは埋まっている」ことをタスクキューに伝えている。
- タスクキュー
- クリックイベントである、
task2 done
をセット - a関数内の
setTimeout(task1 done)
をセット
- クリックイベントである、
- コールスタック
- a関数コンテキストが終了しコールスタックから削除
- グローバルコンテキストが終了しコールスタックから削除
- イベントループ
- コールスタックが空になったことをタスクキューに通知
- タスクキュー
- セットされていた、クリックイベント、setTimeoutを登録した順番でコールスタックにセットする。