[解決済み] イベントループを理解する
質問
考えていて、こんなことを思いつきました。
このコードを下に見てみましょう。
console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);
リクエストが来ると、JSエンジンは上のコードを順次実行し始めます。最初の2つの呼び出しは同期呼び出しです。しかし
setTimeout
メソッドになると、非同期実行になる。しかし、JSはそこからすぐに戻り、実行を継続する、これは
Non-Blocking
または
Async
. そして、それは他の等でも動作し続けます。
この実行結果は次のようになります。
a c d b
つまり、基本的には2番目の
setTimeout
は先に終了し、そのコールバック関数は最初のものよりも早く実行されます。
ここではシングルスレッド・アプリケーションについて話しています。JSエンジンはこれを実行し続け、最初のリクエストを完了しない限り、2番目のリクエストに行きません。しかし、良いことに、JSエンジンは
setTimeout
のようなブロック操作を待たずに、新しいリクエストを受け入れるので、より速くなります。
しかし、私の疑問は以下の項目に関して生じます。
#1:
シングルスレッド・アプリケーションの話であれば、どのようなメカニズムでプロセス
setTimeouts
を処理する一方で、JSエンジンはさらに多くのリクエストを受け付け、それらを実行するのでしょうか?シングルスレッドはどのようにして他のリクエストに対応し続けるのでしょうか?何が
setTimeout
に対して動作し、他のリクエストが入ってきて実行され続けるのでしょうか?
#2:
もし、これらの
setTimeout
関数が裏で実行され、さらにリクエストが来て実行されるのであれば、何が裏で非同期実行を行うのでしょうか?私たちが話している、この
EventLoop
?
#3:
しかし、メソッド全体を
EventLoop
に置くべきで、そうすれば全体が実行され、コールバックメソッドが呼ばれるのでは?これは、コールバック関数について話しているときに私が理解していることです。
function downloadFile(filePath, callback)
{
blah.downloadFile(filePath);
callback();
}
しかしこの場合、JSエンジンはどのようにして非同期関数であることを知り、コールバックを
EventLoop
? おそらく
async
キーワードのようなもの、またはJS Engineが引き受けるメソッドが非同期メソッドであり、それに応じて処理されるべきであることを示す属性のようなものでしょう。
#4: しかし 記事 には、私が推測していたのとはまったく逆のことが書かれています。
イベントループはコールバック関数の待ち行列です。非同期関数が実行されると、コールバック関数がキューに押し込まれます。 関数が実行されると、そのコールバック関数がキューにプッシュされます。このとき が実行されるまで、JavaScript エンジンはイベントループの処理を開始しません。 が実行されるまで、JavaScript エンジンはイベントループの処理を開始しません。
#5: そして、参考になりそうなこの画像がありますが、画像の最初の説明は、質問番号4で述べたことと全く同じことを言っています。
そこで私がここで質問したいのは、上記の項目についての説明を受けることです。
どのように解決するのですか?
<ブロッククオート1: シングルスレッド・アプリケーションの場合、JSエンジンが多くのリクエストを受け付け、それを実行している間、setTimeoutはどのように処理されるのでしょうか?そのシングルスレッドは他のリクエストに対応し続けるのではないでしょうか? 他のリクエストが来て実行され続ける間、誰がsetTimeoutに取り組み続けるのでしょう。
あなたのプログラムのJavaScriptを実際に実行するのは、nodeのプロセスの中で1つのスレッドだけです。しかし、node自体の中では、実際にはイベントループ機構の操作を処理する複数のスレッドがあり、これにはIOスレッドのプールと他の一握りのスレッドが含まれます。重要なのは、これらのスレッドの数が、スレッドパーコネクション並行性モデルのように処理される同時接続の数に対応しないことです。
さて、"setTimeouts" を実行することについてですが、あなたが
setTimeout
を呼び出したとき、node が行うことは基本的に、将来のある時点で実行される関数のデータ構造を更新することです。基本的に、node は実行が必要なもののキューの束を持っており、イベント ループの "tick" ごとに 1 つを選択し、キューから削除して、それを実行するのです。
理解すべき重要なことは、node は重い作業のほとんどを OS に依存しているということです。そのため、入ってくるネットワーク リクエストは実際には OS 自身によって追跡され、ノードがそれを処理する準備ができたら、システム コールを使用して OS に処理可能なデータを含むネットワーク リクエストを要求するだけです。つまり、ノードが行うIOの多くは、「Hey OS, got a network connection with data ready to read?」または「Hey OS, any of my outstanding filesystem calls have data ready?」のどちらかです。nodeは内部アルゴリズムとイベントループエンジンの設計に基づき、実行するJavaScriptを1つ選び、実行し、また同じ処理を繰り返すことになります。これがイベントループの意味するところです。Nodeは基本的に常に「次に実行すべき小さなJavaScriptは何か」を判断して実行しています。これにはOSが完了したIOや、JavaScriptの中で
setTimeout
または
process.nextTick
.
2: もしこれらのsetTimeoutが、より多くのリクエストが来て実行されている間に裏で実行されるなら、裏で非同期実行を行うものは、我々がEventLoopについて話しているものでしょうか?
裏側で実行されるJavaScriptはありません。プログラム内のすべてのJavaScriptは、フロントとセンターで、一度に1つずつ実行されます。裏で起こっていることは、OSがIOを処理し、ノードがその準備を待ち、ノードが実行を待つJavaScriptのキューを管理することです。
3: JS Engineはどのようにして非同期関数であることを知り、EventLoopに入れることができるのでしょうか。
ノードコアには、システムコールを行うため非同期である関数の固定セットがあり、ノードはOSまたはC++を呼び出さなければならないため、これらがどれであるかを知っています。基本的にすべてのネットワークとファイルシステムのIO、および子プロセスのインタラクションは非同期で、JavaScriptがnodeに非同期に何かを実行させる唯一の方法は、nodeコアライブラリが提供する非同期関数のいずれかを呼び出すことで実現できます。独自の API を定義する npm パッケージを使用している場合でも、イベント ループを生成するために、最終的にその npm パッケージのコードは node core の非同期関数の 1 つを呼び出すことになり、そのときに node は tick が完了しイベント ループ アルゴリズムを再び開始できることを認識します。
4 イベントループは、コールバック関数のキューです。非同期関数が実行されると、コールバック関数がキューにプッシュされます。JavaScriptエンジンは、非同期関数が実行された後のコードまで、イベントループの処理を開始しません。
はい、これは本当ですが、誤解を招きかねません。重要なのは、通常のパターンが
//Let's say this code is running in tick 1
fs.readFile("/home/barney/colors.txt", function (error, data) {
//The code inside this callback function will absolutely NOT run in tick 1
//It will run in some tick >= 2
});
//This code will absolutely also run in tick 1
//HOWEVER, typically there's not much else to do here,
//so at some point soon after queueing up some async IO, this tick
//will have nothing useful to do so it will just end because the IO result
//is necessary before anything useful can be done
つまり、フィボナッチ数をメモリ上で同期的にすべて同じ刻みで数えることによって、イベントループを完全にブロックすることができるのです。これは協調的並行処理です。JavaScript の各ティックは、ある程度の合理的な時間内にイベント ループを終了しなければならず、そうでなければアーキテクチャ全体が失敗します。
関連
-
[解決済み】ExpressJS : res.redirect()が期待通りに動かない?
-
モジュールのビルドに失敗しました。Error: ENOENT: no such file or directory, scandir 'D:\.... \node_modules
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] let "と "var "の使い分けは?
-
[解決済み] JavaScriptでメールアドレスを検証するのに最適な方法は何ですか?
-
[解決済み] JavaScriptでオブジェクトをディープクローンする最も効率的な方法は何ですか?
-
[解決済み] package.jsonのチルダ(~)とキャレット(^)の違いは何ですか?
-
[解決済み] event.preventDefault() vs. return false
-
[解決済み] forEachループでasync/awaitを使用する
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JSクロスドメインソリューション リアクト構成 リバースプロキシ
-
JSアレイループと効率解析の比較
-
jsを使った簡単な照明スイッチのコード
-
vue for 登録ページ効果 vue for sms 認証コードログイン
-
vue+webrtc(Tencent cloud)ライブ機能の実践を実現するために
-
VUEグローバルフィルターの概念と留意点、基本的な使い方
-
[解決済み] 配列の結合時に未定義のプロパティ 'push' を読み込むことができない
-
[解決済み】JavaScriptでインラインIF文の書き方は?
-
[解決済み】(Google Map API) Geocodeは以下の理由で成功しませんでした。REQUEST_DENIED
-
JSクリックイベント - Uncaught TypeError: プロパティ 'onclick' に null を設定できません。