Node.jsバージョン0.10が本日リリースされ、導入されました setImmediate
。APIの変更のドキュメントには、再帰やったときに、それを使用することを提案してnextTick
電話を。
何からMDNは述べています、それは非常によく似らしいですprocess.nextTick
。
いつ使用nextTick
すべきsetImmediate
か、いつ使用すべきか?
setImmediate
をより詳細に説明しています。
Node.jsバージョン0.10が本日リリースされ、導入されました setImmediate
。APIの変更のドキュメントには、再帰やったときに、それを使用することを提案してnextTick
電話を。
何からMDNは述べています、それは非常によく似らしいですprocess.nextTick
。
いつ使用nextTick
すべきsetImmediate
か、いつ使用すべきか?
setImmediate
をより詳細に説明しています。
回答:
setImmediate
イベントキューに既にあるI / Oイベントコールバックの背後にある関数をキューに入れる場合に使用します。process.nextTick
現在の関数が完了した直後に実行されるように、イベントキューの先頭で関数を効果的にキューに入れるために使用します。
したがって、再帰を使用して長時間実行されているCPUにバインドされたジョブを分割しようとしている場合は、次の反復をキューに入れるのではsetImmediate
なく、使用することをお勧めします。process.nextTick
反復の間に実行します。
requestAnimationFrame
常に発生するわけではないので回避します(これは間違いなく見ました。例はタブが現在のタブではなかったと思います)。ページがペイントを完了する前に呼び出される可能性があります(つまり、ブラウザはまだビジー状態です)。
例として
import fs from 'fs';
import http from 'http';
const options = {
host: 'www.stackoverflow.com',
port: 80,
path: '/index.html'
};
describe('deferredExecution', () => {
it('deferredExecution', (done) => {
console.log('Start');
setTimeout(() => console.log('TO1'), 0);
setImmediate(() => console.log('IM1'));
process.nextTick(() => console.log('NT1'));
setImmediate(() => console.log('IM2'));
process.nextTick(() => console.log('NT2'));
http.get(options, () => console.log('IO1'));
fs.readdir(process.cwd(), () => console.log('IO2'));
setImmediate(() => console.log('IM3'));
process.nextTick(() => console.log('NT3'));
setImmediate(() => console.log('IM4'));
fs.readdir(process.cwd(), () => console.log('IO3'));
console.log('Done');
setTimeout(done, 1500);
});
});
次の出力が得られます
Start
Done
NT1
NT2
NT3
TO1
IO2
IO3
IM1
IM2
IM3
IM4
IO1
これが違いを理解するのに役立つことを願っています。
更新しました:
コールバックは
process.nextTick()
、他のI / Oイベントが発生する前にrunを使用して延期されますが、setImmediate()を使用すると、実行はすでにキューにあるI / Oイベントの後ろにキューイングされます。Node.js Design Patterns、Mario Casciaro作(おそらくnode.js / jsに関する最高の本)
For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process:
したがって、この回答は実際の違いには答えませんが、異なるコンテキストで変化する可能性のある例にすぎません
私はこれをかなりうまく説明できると思います。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
反復ゼロで関数を呼び出します。これは、2つのハンドラ、のための1つ登録されますsetImmediate
とのための1つをprocess.nextTick
。次にsetImmediate
、次のチェックフェーズで実行されるハンドラーからこの関数を再帰的に呼び出します。nextTick
ハンドラは、それが第二登録された、それは実際に最初に実行されますので、にもかかわらず、イベントループを中断し、現在の操作の終了時に実行されます。
順序は次のようになります。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);
今、我々は再帰呼び出しを移動したことstep
にnextTick
ハンドラ物事異なる順序で動作します。イベントループの最初の反復が実行step
され、setImmedaite
ハンドラーとハンドラーの登録を呼び出しますnextTick
。現在の操作が終了すると、nextTick
ハンドラーが起動し、別のハンドラーだけでなく別のハンドラーも再帰的に呼び出しstep
て登録します。以来登録現在の操作の後、ハンドラ火災、内のハンドラを、ハンドラは、第二のハンドラは、現在のハンドラの動作が終了した直後に実行します。ハンドラは、これまで続けてから、現在のイベントループを防止し、焼成を維持します。私たちはすべてを乗り越えますsetImmediate
nextTick
nextTick
nextTick
nextTick
nextTick
nextTick
ハンドラーが1つ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
、次のイベントループでsetImmediate
起動し、内部から別のハンドラーを設定しても現在のイベントループがまったく中断されないため、通常どおりイベントループのフェーズの実行を継続できます。
お役に立てば幸いです。
PS-2つの関数の名前はnextTick
現在のループの終わりではなく次のイベントループで起動するように聞こえるため、2つの関数の名前を簡単に入れ替えることができ、現在のループの終わりがより「すぐ"次のループの始まりよりも。まあ、それはAPIが成熟し、人々が既存のインターフェースに依存するようになったときに得られるものです。
回答のコメントでは、nextTickがMacrosemanticsからMicrosemanticsに移行したことを明示的に述べていません。
ノード0.9以前(setImmediateが導入されたとき)、nextTickは次のコールスタックの開始時に動作しました。
ノード0.9以降、nextTickは既存の呼び出しスタックの最後で動作しますが、setImmediateは次の呼び出しスタックの先頭にあります
ツールと詳細については、https://github.com/YuzuJS/setImmediateを確認してください
簡単に言えば、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
両方がどのように機能するかを詳しく説明するいくつかの素晴らしい答えがあります。
尋ねられた特定の質問に答えるものを追加するだけです:
いつ使用
nextTick
すべきsetImmediate
か、いつ使用すべきか?
setImmediate
。Node.jsのイベントループ、タイマ、およびprocess.nextTick()
ドキュメントは、次のものが含まれます。
推論
setImmediate()
するのが簡単であり、ブラウザのJSなどのさまざまな環境と互換性のあるコードにつながるため、開発者はすべての場合に使用することをお勧めします。
以前のドキュメントでは、次の原因になるprocess.nextTick
可能性があると警告しています...
これは、再帰的な
process.nextTick()
呼び出しを行うことでI / Oを「枯渇」させることができるため、イベントループがポーリングフェーズに到達できなくなるため、いくつかの悪い状況になります。
process.nextTick
結局のところ、餓死することさえありPromises
ます:
Promise.resolve().then(() => { console.log('this happens LAST'); });
process.nextTick(() => {
console.log('all of these...');
process.nextTick(() => {
console.log('...happen before...');
process.nextTick(() => {
console.log('...the Promise ever...');
process.nextTick(() => {
console.log('...has a chance to resolve');
})
})
})
})
一方、setImmediate
は「推論しやすい」であり、次のタイプの問題を回避します。
Promise.resolve().then(() => { console.log('this happens FIRST'); });
setImmediate(() => {
console.log('this happens LAST');
})
したがって、の固有の動作に特別な必要がない限りprocess.nextTick
、推奨されるアプローチは「すべての場合に使用setImmediate()
する」ことです。
よりよく理解するために、Loop専用のドキュメントセクションを確認することをお勧めします。そこから抜粋したスニペット:
ユーザーに関する限り、似た2つの呼び出しがありますが、その名前は混乱を招きます。
process.nextTick()は同じフェーズですぐに起動します
setImmediate()は、
イベントループの次の反復または「ティック」で起動します
本質的に、名前は交換する必要があります。process.nextTick()はsetImmediate()よりもすぐに起動しますが、これは変更される可能性が低い過去のアーティファクトです。