JavaScriptでのイベントループ
10195 ワード
JavaScriptの仕組み
C、Java、Pythonなどの同期言語は、個別のスレッドやプロセスを使用しない限り、予め作成された順序(同期)でコードを実行します.すなわち,後で記述するコードは,先に記述したコードより先に実行されない.
しかしJavaScriptは非同期言語です.JavaScriptは基本的に単一スレッドで実行されます.1つのプライマリ・スレッドのみで構成され、一度に1つのタスクしか実行できません.他のタスクに手を出すことはできません.次のタスクを実行するには、既存のタスクを完了する必要があります.これらのJavaScriptの非同期性によっては,先にコードを実行する操作が完了する前に,後でコードを実行する操作が先に完了する可能性がある.
function first() {
setTimeout(() => {
console.log("The First function has been called.");
}, 1000);
}
function second() {
setTimeout(() => {
console.log("The Second function has been called.");
}, 500);
}
first();
second();
上からfirst()
、後からsecond()
と呼びます.ただし、上記のコードの実行結果は以下の通りです.
The Second function has been called.
The First function has been called.
実際のfirst()
とsecond()
の実行順序が呼び出し順序と異なるかどうかを知るには、JavaScriptの呼び出しスタックとイベントループを知る必要があります.コールスタック
JavaScriptは、呼び出した関数をスタック形式の呼び出しスタックに追加し、実行する関数(Pop)を削除します.
function foo(b) {
var a = 10;
return a + b + 11;
}
function bar(x) {
var y = 3;
return foo(x * y);
}
console.log(bar(7));
bar()
が呼び出されると、bar
のパラメータおよび領域変数を含むフレームがcallスタックにプッシュされ、bar
がfoo
を呼び出し、foo
のパラメータおよび領域変数を含むフレームがcallスタックにプッシュされる.foo
の実行が終了すると、foo
はcallスタックからポップアップされ、bar
フレームもcallスタックからポップアップされ、callスタックは空になります.bar呼び出し→foo呼び出し→foo終了→bar終了
callstackとは何か知っている以上、上のコードをもう一度見てみましょう.
function first() {
setTimeout(() => {
console.log("The First function has been called.");
}, 1000);
}
function second() {
setTimeout(() => {
console.log("The Second function has been called.");
}, 500);
}
first();
second();
JavaScriptはcallスタックが1つしかないと言っていますが、first()
とsecond()
のsetTimeout(() ⇒ {}, time)
を同時に管理するにはどうすればいいのでしょうか.実際、上図のように、Memory HeapやCall Stackを含むJavaScriptエンジンに加えて、JavaScriptの実行に関連する要因もいくつか存在します.Wep API、Event Loop、Callback Queue.
setTimeout
を実行すると、JavaScriptエンジンはsettimeoutのコールバック関数と時間をWeb APIに送信します.その後、Web APIはsettimeoutタスクを実行し、設定された時間(1000ms or 500ms
)の後にコールバック関数(console.log(...)
)をCallback Queueに渡す.コールバックキューとイベントループ
event loopは、コールバックスタックが空になるまで、コールバックキュー内のコールバック関数(メッセージ)を処理し続けます.
イベントループの実装方法は次のとおりです.
while (queue.waitForMessage()) {
queue.processNextMessage();
}
イベントループは、キューに新しいメッセージがあるたびに次のメッセージを処理します.キューにメッセージがない場合は、同期して新しいメッセージの到着を待機します.
Run to completion scheduling(nonpreemptive scheduling)
JavaScriptのコールバックキューでは、現在のメッセージが完全に処理されるまで、次のメッセージの処理が開始されません.
メッセージ処理時間が長すぎると、Webブラウザに次のエラー画面が表示されます.
このような状況を回避するためには、メッセージ処理時間をできるだけ短縮し、1つのメッセージを複数のメッセージに分割する必要があります.
JavaScriptはsettimeoutの2番目の引数の時間値の遅延を保証しません.時間の最小遅延を表すだけです.
理由はJavaScriptのRun to Completionスケジューリングです.
イベントloopはRun to completionに従ってスケジューリングされるため、キュー内のタスクは順次処理され、ダイヤルバックメッセージが処理されます.
参考資料
JavaScript動作原理(Single Thread、Event Loop、Asynchronous)
非同期Javascript-単一スレッドベースのJSの非同期処理方法-Hudi-類似プログラマー
モデルとイベントループの同期
Reference
この問題について(JavaScriptでのイベントループ), 我々は、より多くの情報をここで見つけました https://velog.io/@koreanhole/JavaScript의-Event-Loopテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol