node.js nextTick vs setImmediate,直观的解释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17502948/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 14:57:42  来源:igfitidea点击:

nextTick vs setImmediate, visual explanation

node.js

提问by Gabriel Llamas

I'm very confused about the differences between nextTick and setImmediate. I've read all the documentation about them on the internet but I still don't understand how they work.

我对 nextTick 和 setImmediate 之间的差异感到非常困惑。我已经阅读了互联网上关于它们的所有文档,但我仍然不明白它们是如何工作的。

Examples:

例子:

function log(n) { console.log(n); }

setImmediate

立即设置

setImmediate(function() {
  setImmediate(function() {
    log(1);
    setImmediate(function() { log(2); });
    setImmediate(function() { log(3); });
  });
  setImmediate(function() {
    log(4);
    setImmediate(function() { log(5); });
    setImmediate(function() { log(6); });
  });
});

//1 2 3 4 5 6

nextTick

下一个滴答声

process.nextTick(function() {
  process.nextTick(function() {
    log(1);
    process.nextTick(function() { log(2); });
    process.nextTick(function() { log(3); });
  });
  process.nextTick(function() {
    log(4);
    process.nextTick(function() { log(5); });
    process.nextTick(function() { log(6); });
  });
});

//1 4 2 3 5 6

Why these results? Please explain with a visual or very easy to follow explanation. Even the node core devs don't agree at how nextTick and setImmediate should be understood by people.

为什么会有这些结果?请用视觉或非常容易理解的解释来解释。甚至节点核心开发人员也不同意人们应该如何理解 nextTick 和 setImmediate。

Sources:

资料来源:

回答by Dave Stibrany

Consider the following two examples:

考虑以下两个示例:

setImmediate

立即设置

setImmediate(function A() {
  setImmediate(function B() {
    log(1);
    setImmediate(function D() { log(2); });
    setImmediate(function E() { log(3); });
  });
  setImmediate(function C() {
    log(4);
    setImmediate(function F() { log(5); });
    setImmediate(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 'TIMEOUT FIRED' 1 4 2 3 5 6
// OR
// 1 'TIMEOUT FIRED' 4 2 3 5 6

nextTick

下一个滴答声

process.nextTick(function A() {
  process.nextTick(function B() {
    log(1);
    process.nextTick(function D() { log(2); });
    process.nextTick(function E() { log(3); });
  });
  process.nextTick(function C() {
    log(4);
    process.nextTick(function F() { log(5); });
    process.nextTick(function G() { log(6); });
  });
});

setTimeout(function timeout() {
  console.log('TIMEOUT FIRED');
}, 0)

// 1 4 2 3 5 6 'TIMEOUT FIRED'

setImmediate callbacks are fired off the event loop, once per iteration in the order that they were queued. So on the first iteration of the event loop, callback A is fired. Then on the second iteration of the event loop, callback B is fired, then on the third iteration of the event loop callback C is fired, etc. This prevents the event loop from being blocked and allows other I/O or timer callbacks to be called in the mean time (as is the case of the 0ms timeout, which is fired on the 1st or 2nd loop iteration).

setImmediate 回调从事件循环中触发,每次迭代一次,按照它们排队的顺序。所以在事件循环的第一次迭代中,回调 A 被触发。然后在事件循环的第二次迭代中,回调 B 被触发,然后在事件循环的第三次迭代中,回调 C 被触发,依此类推。这可以防止事件循环被阻塞并允许其他 I/O 或计时器回调同时调用(就像 0ms 超时的情况一样,它在第一次或第二次循环迭代中被触发)。

nextTick callbacks, however, are always fired immediately after the current code is done executing and BEFORE going back to the event loop. In the nextTick example, we end up executing all the nextTick callbacks before ever returning to the event loop. Since setTimeout's callback will be called from the event loop, the text 'TIMEOUT FIRED' will not be output until we're done with every nextTick callback.

然而,nextTick 回调总是在当前代码执行完成后和返回事件循环之前立即触发。在 nextTick 示例中,我们最终会在返回事件循环之前执行所有 nextTick 回调。由于 setTimeout 的回调将从事件循环中调用,因此在我们完成每个 nextTick 回调之前,不会输出文本“TIMEOUT FIRED”。

回答by gsalgadotoledo

According the Node.js doc names of these two function are exactly swapped

根据这两个函数的 Node.js 文档名称完全交换

setImmediate() (BEST RECOMMENDED)

setImmediate()(最佳推荐

It's fire first at event queue

它首先在事件队列中触发



process.nextTick() (USE FOR SPECIAL CASES see example later on)

process.nextTick()(用于特殊情况,见后面的例子

It's fire immediately, It's kinda write an statement more at the end at the current file

马上就火了,有点像在当前文件的末尾多写一条语句



If we have this code

如果我们有这个代码

setTimeout(function(){
  console.log('Hello world 5'); // It's waiting like a normal person at a queue
}, 0);

setImmediate(function(){
  console.log('Hello world 4'); 
  // It's like get to last and be take care of first 
  // but always after of .nextTick and before of setInterval(, 0)
});

process.nextTick(function(){
   console.log('Hello world 3'); // It's like be at the bottom at this file
});

console.log('Hello world 1');
console.log('Hello world 2');

A visual explanation as per your request:

根据您的要求提供视觉说明:

enter image description here

在此处输入图片说明

Cases for use process.nextTick() when you have to emit and event before to handled it:

当您必须在处理它之前发出和事件时使用 process.nextTick() 的情况:

const EventEmitter = require('events');
const util = require('util');

function MyEmitter() {
  EventEmitter.call(this);

  // use nextTick to emit the event once a handler is assigned
  process.nextTick(function () {
    this.emit('event');
  }.bind(this));
}
util.inherits(MyEmitter, EventEmitter);

const myEmitter = new MyEmitter();
myEmitter.on('event', function() {
  console.log('an event occurred!');
});

Look at this vide where Philip Robertsgive us a great explanation about runtime event loop and look at this online eventloop debugger Live test how event loop works

看看这个视频,菲利普罗伯茨给了我们一个关于运行时事件循环的很好的解释,看看这个在线事件循环调试器现场测试事件循环是如何工作的

Source: https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate

来源:https: //github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate

回答by freakish

I can't reproduce your results for setImmediate. It should be the same as nextTick(and it is in my tests) since in this situation they do pretty much the same thing. The only reasonable explanation for that is that setImmediateis somehow synchronous, but it is not.

我无法重现您的结果setImmediate。它应该与nextTick(并且在我的测试中)相同,因为在这种情况下它们做的事情几乎相同。对此唯一合理的解释是setImmediate在某种程度上是同步的,但事实并非如此。

And according to NodeJS documentationthe only real difference is that multiple nextTickmay fire in one loop iteration (depending on maxTickDepth), while setImmediatefires once per iteration.

根据NodeJS 文档,唯一真正的区别是nextTick在一次循环迭代中可能会触发多个(取决于maxTickDepth),而setImmediate每次迭代会触发一次。

回答by Venkat.R

Below gives you better clarity.

下面给你更好的清晰度。

setImmediate

立即设置

  1. It's execute a script once the current poll phase completes.
  2. It's a timer module function and timer functions are global, you can call them without require.
  3. It can cleared by clearImmediate().
  4. Set "immediate" execution of the callback after I/O events' callbacks before setTimeout() and setInterval().
  1. 一旦当前轮询阶段完成,它就会执行一个脚本。
  2. 它是一个定时器模块函数,定时器函数是全局的,你可以不用require.
  3. 它可以通过 clearImmediate() 清除。
  4. 在 setTimeout() 和 setInterval() 之前,在 I/O 事件的回调之后设置回调的“立即”执行。

nextTick

下一个滴答声

  1. It's a process global object function of NodeJS.
  2. All callbacks passed to process.nextTick() will be resolved before the event loop continues.
  3. Allow users to handle errors.
  4. Helps to try the request again before the event loop continues.
  1. 它是 NodeJS 的进程全局对象函数。
  2. 传递给 process.nextTick() 的所有回调将在事件循环继续之前解决。
  3. 允许用户处理错误。
  4. 有助于在事件循环继续之前再次尝试请求。

Simple code Snippet.

简单的代码片段。

console.log("I'm First");

setImmediate(function () {
  console.log('Im setImmediate');
});

console.log("I'm Second");

process.nextTick(function () {
  console.log('Im nextTick');
});

console.log("I'm Last");

/*
Output
$ node server.js
I'm First
I'm Second
I'm Last
Im nextTick
Im setImmediate
*/

回答by Guichi

I think all the answers above are obsolete, because I got different answers constantly with the current version of nodejs and it is easy to reason about

我认为上面的所有答案都过时了,因为我在当前版本的 nodejs 中不断得到不同的答案,这很容易推理

var log=console.log
log(process.version)

var makeAsyncCall
if(false)
    makeAsyncCall=setImmediate
else
    makeAsyncCall=process.nextTick;

makeAsyncCall(function A () {
    makeAsyncCall(function B() {
        log(1);
        makeAsyncCall(function C() { log(2); });
        makeAsyncCall(function D() { log(3); });
    });
    makeAsyncCall(function E() {
        log(4);
        makeAsyncCall(function F() { log(5); });
        makeAsyncCall(function G() { log(6); });
    });
});
//1
//4
//2
//3
//5
//6
//in both case

After reading https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediatelet use start from setImmediatewe should keep track of the check queuebecause it is where the setImmediatecallback reside.

阅读https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-setimmediate 后让使用从setImmediate我们应该跟踪的check queue,因为它是在哪里setImmediate回调所在的位置。

First iteration

第一次迭代

Ais push to check queue

A推到 check queue

check queue :[A]

检查队列:[A]

Second iteration

第二次迭代

Ais pull out from queueto execute

A被拉出queue执行

During its execution ,it put Band Eto queueand then, Acomplete and start next iteration

在它的执行过程中,它 put Band Etoqueue然后,A完成并开始下一次迭代

check queue :[B,E]

检查队列:[B,E]

Third iteration

第三次迭代

pull out Band push CD

拉出B并推CD

check queue :[E,C,D]

检查队列:[E,C,D]

Forth iteration

第四次迭代

pull out Eand push FG

拉出E并推FG

check queue : [C,D,F,G]

检查队列:[C,D,F,G]

Finally

最后

execute the callbacks in the queue sequentially

依次执行队列中的回调

For nextTickcase, the queue works exactly the same way,that is why it produce same result

例如nextTick,队列的工作方式完全相同,这就是它产生相同结果的原因

The different is that :

不同的是:

the nextTickQueue will be processed after the current operation completes, regardless of the current phase of the event loop

nextTickQueue 将在当前操作完成后被处理,而不管事件循环的当前阶段

To be clear,the event loop maintain multiple queues and check queueis just one of them,the node will decide which queue to use based on some rules

需要说明的是,事件循环维护多个队列并且check queue只是其中之一,节点将根据一些规则决定使用哪个队列

with process.nextTickhowever,it is sort of bypassing all the rule and execute the callback in nextTickimmediately

process.nextTick然而,这是有点绕过所有的规则,并在执行回调nextTick立即