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
- 一旦当前的调查阶段完成,它就执行一个脚本。
- 这是一个定时器模块function和定时器function是全球性的,你可以打电话给他们没有
require
。 - 它可以通过clearImmediate()清除。
- 在setTimeout()和setInterval()之前的I / O事件callback之后,设置callback的“即时”执行。
nextTick
- 它是NodeJS的一个进程全局对象函数。
- 传递给process.nextTick()的所有callback将在事件循环继续之前parsing。
- 允许用户处理错误。
- 有助于在事件循环继续之前再次尝试请求。
简单的代码片段。
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
开始,我们应该跟踪因为它是setImmediate
callback驻留的地方。
第一次迭代
A
是推动check queue
检查队列:[A]
第二次迭代
A
从queue
拉出来执行
在执行过程中,它将B
和E
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