367

Node.js バージョン 0.10 が本日リリースされ、導入されまし setImmediateた。APIの変更に関するドキュメントでは、再帰nextTick呼び出しを行うときに API を使用することが提案されています。

MDN の言うことから、それはprocess.nextTick.

いつ使用するnextTick必要がありますsetImmediateか?

4

9 に答える 9

65

私はこれを非常にうまく説明できると思います。nextTickは現在の操作の最後に呼び出されるため、再帰的に呼び出すと、イベント ループの続行が妨げられる可能性があります。setImmediateイベント ループのチェック フェーズで起動することでこれを解決し、イベント ループを正常に続行できるようにします。

   ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘

ソース: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

チェック フェーズはポーリング フェーズの直後であることに注意してください。これは、ポーリング フェーズと I/O コールバックが、呼び出しがsetImmediate実行される可能性が最も高い場所であるためです。したがって、理想的には、これらの呼び出しのほとんどは実際には非常に即時であり、nextTickすべての操作の後にチェックされ、技術的にはイベント ループの外に存在するものほど即時ではありません。

setImmediateとの違いの例を少し見てみましょうprocess.nextTick

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from setImmediate handler.
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
  });
}
step(0);

このプログラムを実行したばかりで、イベント ループの最初の反復を実行しているとします。step反復ゼロで関数を呼び出します。setImmediate次に、 用と用の 2 つのハンドラを登録しますprocess.nextTicksetImmediate次に、次のチェック フェーズで実行されるハンドラーからこの関数を再帰的に呼び出します。ハンドラーはnextTick、イベント ループを中断する現在の操作の最後に実行されるため、2 番目に登録されていても、実際には最初に実行されます。

最終的な順序は次のとおりです。nextTick現在の操作が終了すると起動し、次のイベント ループが開始し、通常のイベント ループ フェーズが実行され、起動し、プロセスを最初からやり直すために関数をsetImmediate再帰的に呼び出します。step現在の営業終了、nextTick火災等

上記のコードの出力は次のようになります。

nextTick iteration: 0
setImmediate iteration: 0
nextTick iteration: 1
setImmediate iteration: 1
nextTick iteration: 2
setImmediate iteration: 2
nextTick iteration: 3
setImmediate iteration: 3
nextTick iteration: 4
setImmediate iteration: 4
nextTick iteration: 5
setImmediate iteration: 5
nextTick iteration: 6
setImmediate iteration: 6
nextTick iteration: 7
setImmediate iteration: 7
nextTick iteration: 8
setImmediate iteration: 8
nextTick iteration: 9
setImmediate iteration: 9

stepではなく、への再帰呼び出しをnextTickハンドラに移動しましょうsetImmediate

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from nextTick handler.
  });
}
step(0);

再帰呼び出しをハンドラーに移動しstepnextTickので、別の順序で動作します。イベント ループの最初の繰り返しが実行され、ハンドラーとハンドラーstepの登録が呼び出されます。現在の操作が終了すると、ハンドラーが起動し、別のハンドラーと別のハンドラーを再帰的に呼び出して登録します。ハンドラーは現在の操作の後に起動するため、ハンドラー内にハンドラーを登録すると、現在のハンドラー操作が終了した直後に 2 番目のハンドラーが実行されます。ハンドラーは起動し続け、現在のイベント ループが継続するのを防ぎます。私たちはすべてを乗り越えますsetImmedaitenextTicknextTickstepsetImmediatenextTicknextTicknextTicknextTicknextTicknextTick単一のsetImmediateハンドラーが起動する前に、ハンドラー。

上記のコードの出力は次のようになります。

nextTick iteration: 0
nextTick iteration: 1
nextTick iteration: 2
nextTick iteration: 3
nextTick iteration: 4
nextTick iteration: 5
nextTick iteration: 6
nextTick iteration: 7
nextTick iteration: 8
nextTick iteration: 9
setImmediate iteration: 0
setImmediate iteration: 1
setImmediate iteration: 2
setImmediate iteration: 3
setImmediate iteration: 4
setImmediate iteration: 5
setImmediate iteration: 6
setImmediate iteration: 7
setImmediate iteration: 8
setImmediate iteration: 9

再帰呼び出しを中断せず、10 回の反復後に中止した場合、呼び出しは再帰をnextTick続け、イベント ループが次のフェーズに進むことはありません。これは、nextTick再帰的に使用するとブロッキングになる可能性がありますがsetImmediate、次のイベント ループで発生し、setImmediate1 つのイベント ループ内から別のハンドラーを設定しても、現在のイベント ループはまったく中断されず、イベント ループのフェーズを通常どおり実行し続けることができます。

それが役立つことを願っています!

nextTickPS - 2 つの関数の名前は、現在のループの終わりではなく次のイベント ループで起動するように聞こえるため、簡単に交換できるという他のコメンターに同意します。現在のループの終了はより「即時」です。 "次のループの開始より。まあ、それは API が成熟し、人々が既存のインターフェースに依存するようになるにつれて得られるものです。

于 2017-05-31T03:19:34.637 に答える
30

回答のコメントでは、nextTick がマクロセマンティクスからマイクロセマンティクスに移行したことを明示的に述べていません。

ノード 0.9 より前 (setImmediate が導入されたとき)、nextTick は次の呼び出しスタックの開始時に動作しました。

ノード 0.9 以降、nextTick は既存の呼び出しスタックの最後で動作しますが、setImmediate は次の呼び出しスタックの最初で動作します。

ツールと詳細については、https://github.com/YuzuJS/setImmediateをご覧ください。

于 2015-01-27T01:44:10.470 に答える
11

簡単に言えば、process.NextTick() はイベント ループの次のティックで実行されます。ただし、setImmediate には基本的に別のフェーズがあり、setImmediate() で登録されたコールバックが IO コールバックおよびポーリング フェーズの後にのみ呼び出されるようにします。

わかりやすい説明については、このリンクを参照してください: https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and -its-metrics-c4907b19da4c

簡略化されたイベント ループ イベント

于 2017-12-29T10:05:38.773 に答える