blog

ノードのイベントループ

ブラウザには、マクロ・キューとマイクロ・キューの2つのイベント・キューしかありません。nodeでは、イベントループの各部分のキューがあります。 ここで実行するタスクがあれば、このタスクキューを空にしま...

Jan 28, 2020 · 4 min. read
シェア

nodeのイベントループは、ブラウザのイベントループとは全く異なります。

ブラウザのイベントキューはマクロキューとマイクロキューの2つだけです。一方、nodeでは、イベントループの各部分ごとにキューがあります。

キュー内のすべてのタスクがこのステージで実行された後にのみ、次のステージはタスクキューを空にします。

timers

タイマーを保存するコールバック関数

poll ポーリング・キュー

ここには、タイムチェックキューを除くほとんどすべてのコールバック関数があります。

例:ファイル読み込みコールバック リクエストをリッスンするコールバック

checks

setImmediateのコールバック関数は、直接チェックキューに送られます。

全体のプロセスは整理されています

ノードは最初にグローバルな同期コードを実行し、タイマーに遭遇すると、タイミングをとるためにタイマースレッドに入れ、setImmediateに遭遇すると、直接チェックキューに入れ、残りの非同期操作は一般的にポーリングキューに入れます。

  1. イベントループがタイマーに向かい、タイマースレッドがすべてのタイマーを受け取り、カウントして、タイマーが上がっているかどうかを確認します。

    • 時間であれば、コールバックを取り出し、時間であるすべてのコールバックが実行され、次のキューに移動するまで実行します。
    • 時間切れでなければ、そのまま次のキューへ

ここでは、実際には、タイマーが厳密にキューではないことに注意してください、それはタイマーのタイミングが理由の一つに許可されていない理由は、この計算のために、時間がないかどうかを確認するためにタイマー計算のうち、タイミングスレッドからです。

  1. 投票キューへ

    • ここで実行すべきタスクがなければ、他のキューで実行すべきタスクがあるかどうかを確認します。
      • もし実行すべきタスクがなければ、他のキューに実行すべきタスクがあるまでこのキューで待ち、それから次のキューに移動します。
      • 他のキューに実行すべきタスクがない場合、次のキューに移動するためにポーリングキューで十分に待ちます。
    • ここで実行するタスクがある場合は、このタスク・キューを空にします。
  2. チェック・キューへ。

    次の段階に進む前にキューを空にします。

setTimeout(() => {
 console.log(1)
}, 0)
fs.readFile('./index.js', (err, data) => {
 console.log(2)
})
setImmediate(() => {
 console.log(3)
})
console.log(4)
// 4 1 3 2
まず、グローバル同期コードを実行し、タイマーをタイマースレッドに入れ、ファイルを読み込みをpollに入れ、setImmediateをchecksに入れ、4を出力する。
時間ループに入り、タイムアウトが終了したら、それを取り出して実行する。
ファイルを読むと、ポーリング待機になるはずだが、チェックにタスクがあることがわかった。
チェックと出力3に進む
次のループに進む。 タイマーに移動し、ポールに到達し、待機し、ファイルを読み、2を出力し、待機し、これ以上タスクがないことを確認する。
 
  • 銘記

setTimeout 0とsetImmediateが実行される順番は、その時のシステムの環境によって、必ずしも先に分析したようにスムーズであるとは限らず、カードがスタックしているかどうかによって実行される順番が変わることもあります。

でも、今回のような場合は違います。

fs.readFile('./index.js', (err, data) => {
 setTimeout(() => {
 console.log(1)
 }, 0)
 setImmediate(() => {
 console.log(2)
 })
})

コンピュータが遅延しているかどうかにかかわらず、2 1を出力し、その理由を分析します。

1. ファイルの読み込みがあり、イベントループに入る。
2. タイマーはない。 ポールに行く。
3. 他のイベントはなく、ポーリングでファイルが読み込まれるのを待っている。
4. ファイルの読み込みに成功したら、コールバックが実行され、timerにタイマーが、checksにsetImmediateが投げ込まれる。
5. この時点で、他のキューにはタスクがあり、ポールは空になり、次のキュー、チェックに移る。
6. だから、まず間違いなく2が出力される。 

NODEのマクロキュー、マイクロキュー

nodeでは、nextTickキューとpromiseキューはイベントループの一部ではない2つのキューです。

マクロ・キューとマイクロ・キューを使ってノード内のイベント処理の順序を区別したいのであれば、先に分析したものはすべてマクロ・キューであり、タイマ・チェック・ポールはすべてマクロ・キューです。そしてnextTick promiseはすべてマイクロキューです。

ノードでは、次の操作に移るには、まずマイクロキューを空にする必要があります。

このプログラムをご覧ください

setImmediate(() => {
 console.log(1)
})
Promise.resolve().then(() => {
 console.log(2)
 process.nextTick(() => {
 console.log(3)
 })
})
process.nextTick(() => {
 console.log(4)
 process.nextTick(() => {
 console.log(5)
 })
})
console.log(6)

アウトプットの順番は?

1. プログラムは順番に実行され、setImmediateコールバックをチェックに入れる。
2. nextTickコールバックをnextTickキューに入れる。
3. Promiseを入れる.then中のコールバックは Promiseキューに入れられる。
4. 出力 6
5. タイマー・キューに入るには、マイクロタスク・キューを空にする。
6. まず、nextTickキューを空にして4を出力し、nextTickにコールバックを登録する。
7. nextTickキューを空にして5を出力する。
8. Promise "キューを空にして、2を出力し、nextTickキューにコールバックを投げる。
9. nextTickキューを空にして3を出力する。
10. マイクロタスクのキューがクリアされ、タイマーに移動し、ポーリングに移動し、チェックに移動する。
11. 出力1

つまり、全体の出力順は6 4 5 2 3 1となります。

Read next

プログラマーの日常生活 あなたはプログラマーに転職するのに適した人間だろうか?

プログラマーは高給取りというイメージが強いですが、プログラミングは誰にでもできる仕事なのでしょうか?プログラマーの日常をご案内しましょう。 父:ああ、わかった、南のバザールへ行って米を50キロ買って帰ってきなさい。 父:1分経ちました。 ..... 息子はドアをひったくると、さっと視界から消えました。 チクタク.電話が鳴ります。 父:息子よ、米はいらないから、北のバザールへ行ってキャベツを60キロ買って帰ってこい、あと5分だ......。

Jan 28, 2020 · 2 min read