Node.js nextTick vs setImmediate,直观解释
我很困惑nextTick和setImmediate之间的区别。我已经在互联网上阅读了所有关于它们的文档,但我仍然不明白它们是如何工作的 示例:Node.js nextTick vs setImmediate,直观解释,node.js,Node.js,我很困惑nextTick和setImmediate之间的区别。我已经在互联网上阅读了所有关于它们的文档,但我仍然不明白它们是如何工作的 示例: function log(n) { console.log(n); } setImmediate setImmediate(function() { setImmediate(function() { log(1); setImmediate(function() { log(2); }); setImmediate(fun
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
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() {
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
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'
为什么会有这些结果?请用直观的或易于理解的解释进行解释。即使是节点核心开发人员也不同意人们应该如何理解nextTick和setImmediate
资料来源:
- 我无法为
setImmediate
复制您的结果。它应该与nextTick(在我的测试中)相同,因为在这种情况下,它们做的事情几乎相同。唯一合理的解释是,setImmediate
在某种程度上是同步的,但它不是
根据唯一的实际区别,多个
nextTick
可能在一次循环迭代中触发(取决于maxTickDepth
),而setImmediate
每次迭代触发一次。考虑以下两个示例:
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
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() {
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
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回调从事件循环中触发,每次迭代按其排队顺序触发一次。因此,在事件循环的第一次迭代中,将触发回调。然后在事件循环的第二次迭代中,启动回调B,然后在事件循环的第三次迭代中启动回调C,等等。这可以防止事件循环被阻塞,并允许在平均时间内调用其他I/O或计时器回调(与在第一次或第二次循环迭代中启动的0ms超时的情况相同)
但是,nextTick回调总是在当前代码执行完毕之后以及返回事件循环之前立即触发。在nextTick示例中,我们在返回事件循环之前执行所有nextTick回调。由于setTimeout的回调将从事件循环中调用,因此在完成每个nextTick回调之前,不会输出文本“TIMEOUT FIRED”。根据Node.js,这两个函数的doc名称是 setImmediate()(最佳推荐) 这是事件队列中的第一个火灾
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()之前必须发出和事件的情况下,使用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!');
});
请看这段视频,其中为我们提供了有关运行时事件循环的详细解释,并查看此在线事件循环调试器
资料来源:
我认为上面所有的答案都过时了,因为我在当前版本的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
读后
让我们使用start fromsetImmediate
我们应该跟踪检查队列,因为它是setImmediate
回调所在的位置
第一次迭代
A
被推送到检查队列
检查队列:[A]
第二次迭代
A
从队列中拉出执行
在执行过程中,它将B
和E
放入队列
,然后,A
完成并开始下一次迭代
检查队列:[B,E]
第三次迭代
拉出B
并推C
D
检查队列:[E、C、D]
第四次迭代
拉出E
并推F
G
检查队列:[C、D、F、G]
最后
按顺序执行队列中的回调
对于nextTick
情况,队列的工作方式完全相同,这就是它产生相同结果的原因
不同之处在于:
将在当前操作后处理nextTickQueue
完成,与事件循环的当前阶段无关
需要说明的是,事件循环维护多个队列,check queue
只是其中之一,节点将根据一些规则决定使用哪个队列
然而,对于process.nextTick
,它有点绕过所有规则,并立即执行下面nextTick
中的回调,从而使您更清晰
一旦当前轮询阶段完成,将执行一个脚本李>
这是一个定时器模块函数,定时器函数是全局函数,您可以调用它们,而无需require
李>
它可以通过clearImmediate()清除李>
在setTimeout()和setInterval()之前的I/O事件回调之后,设置回调的“立即”执行李>
它是NodeJS的一个进程全局对象函数李>
在事件循环继续之前,将解析传递给process.nextTick()的所有回调李>
允许用户处理错误李>
帮助在事件循环继续之前重试请求李>
简单的代码片段。
很好,最后一段是理解主要区别的关键。您的nextTick示例有不同的输出:TIMEOUT FIRED 1 4 2 3 5 6
您正在运行哪个版本的节点?在节点0.10.x上,在点击事件循环之前,您应该始终运行nextTick回调。我希望他们选择不同的名称。现在“nextTick”比setImmediate更直接。@struglingcoder因为当A执行时,它将B和C设置为下一个计划。当B执行时,它将D和E设置为下一个调度,但C已经被安排在B之后。记住,调度或注册回调的时间与实际触发回调的时间是有区别的。好问题。这是一个很好的方法