nextTick vs setImmediate,视觉解释

我很困惑nextTick和setImmediate之间的差异。 我已经阅读了关于他们在互联网上的所有文件,但我仍然不明白他们如何工作。

例子:

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 

为什么这些结果? 请用视觉或非常容易解释说明。 即使是节点核心开发人员也不同意人们如何理解nextTick和setImmediate。

资料来源:

  • setImmediate与nextTick
  • 为什么setImmediate比nextTick慢得多?
  • setImmediate并不总是非常直接的

考虑以下两个例子:

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' 

setImmediatecallback在事件循环中被触发,每次迭代按照它们排队的顺序进行一次。 所以在事件循环的第一次迭代中,callbackA被触发。 然后在事件循环的第二次迭代中,callbackB被触发,然后在事件循环的第三次迭代中C被触发,等等。这可以防止事件循环被阻塞,并允许其他I / O或定时器callback同时调用(就像在第一次或第二次循环迭代中触发的0ms超时一样)。

然而nextTickcallback函数总是在当前代码执行完毕之后立刻被触发,然后再回到事件循环。 在下一个示例中,我们最终会在返回到事件循环之前执行所有nextTickcallback。 由于setTimeout的callback函数将从事件循环中调用,所以直到我们完成每个下一个Tickcallback之后,文本“TIMEOUT FIRED”才会被输出。

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

setImmediate()( BEST推荐

在事件队列中首先发生火灾


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

马上火了,在当前文件最后还是写了一个声明


如果我们有这个代码

 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'); 

视觉上的解释可能是(如你所问):

在这里输入图像说明

使用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!'); }); 

看看这个非常棒的方式Philip Roberts给出了一个运行时事件循环解释和他的运行时事件在线实时testing事件循环是如何工作的

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

我无法重现setImmediate的结果。 它应该和nextTick (在我的testing中),因为在这种情况下,它们几乎是一样的。 唯一合理的解释是setImmediate是某种同步的,但事实并非如此。

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

下面给你更清晰。

setImmediate

  1. 一旦当前的调查阶段完成,它就执行一个脚本。
  2. 这是一个定时器模块function和定时器function是全球性的,你可以打电话给他们没有require
  3. 它可以通过clearImmediate()清除。
  4. 在setTimeout()和setInterval()之前的I / O事件callback之后,设置callback的“即时”执行。

nextTick

  1. 它是NodeJS的一个进程全局对象函数。
  2. 传递给process.nextTick()的所有callback将在事件循环继续之前parsing。
  3. 允许用户处理错误。
  4. 有助于在事件循环继续之前再次尝试请求。

简单的代码片段。

 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 */ 

我认为上面所有的答案已经过时了,因为我不断地用当前版本的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 

在阅读https://github.com/nodejs/node/blob/master/doc/topics/the-event-loop-timers-and-nexttick.md#processnexttick-vs-intimmediate让我们从;setImmediate开始,我们应该跟踪因为它是setImmediatecallback驻留的地方。

第一次迭代

A是推动check queue

检查队列:[A]

第二次迭代

Aqueue拉出来执行

在执行过程中,它将BE queue ,然后A完成并开始下一次迭代

检查队列:[B,E]

第三次迭代

拔出B并按下C D

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

第四次迭代

拔出E并按下F G

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

最后

按顺序执行队列中的callback

对于nextTick情况,队列工作方式完全一样,这就是为什么它产生相同的结果

不同的是:

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

要清楚的是,事件循环维护多个队列,而check queue只是其中的一个,节点将根据一些规则决定使用哪个队列

process.nextTick然而,它是绕过所有的规则,立即在nextTick执行callback