今天发布了Node.js 0.10版本,引入了setImmediate
,API changes文档建议在进行递归nextTick
调用时使用它。
从什么MDN says似乎非常类似于process.nextTick
。
什么时候应该使用nextTick
,什么时候应该使用setImmediate
?
今天发布了Node.js 0.10版本,引入了setImmediate
,API changes文档建议在进行递归nextTick
调用时使用它。
从什么MDN says似乎非常类似于process.nextTick
。
什么时候应该使用nextTick
,什么时候应该使用setImmediate
?
8条答案
按热度按时间mepcadol1#
如果要将函数排在事件队列中已存在的任何I/O事件回调之后,请使用
setImmediate
。使用process.nextTick
可有效地将函数排在事件队列的头部,以便在当前函数完成后立即执行。因此,如果您试图使用递归分解一个长时间运行的CPU密集型作业,您现在可能希望使用
setImmediate
而不是process.nextTick
来对下一次迭代进行排队,否则任何I/O事件回调都没有机会在迭代之间运行。tkqqtvp12#
举例来说:
将给出以下输出
我希望这能帮助我们理解其中的区别。
更新日期:
使用
process.nextTick()
延迟的回调在任何其他I/O事件触发之前运行,而使用setImmediate(),执行将排在队列中已存在的任何I/O事件之后。93ze6v8z3#
我想我可以很好地说明这一点。由于
nextTick
是在当前操作结束时调用的,递归调用它可能会阻止事件循环继续。setImmediate
通过在事件循环的检查阶段触发来解决这个问题,允许事件循环正常继续。来源:https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/
请注意,检查阶段紧接着轮询阶段。这是因为轮询阶段和I/O回调是最有可能运行对
setImmediate
的调用的地方。因此,理想情况下,这些调用中的大多数实际上都是非常即时的,只是不像nextTick
那样即时,nextTick
在每次操作后都要检查,技术上存在于事件循环之外。让我们看一个
setImmediate
和process.nextTick
之间差异的小例子:假设我们刚刚运行了这个程序,正在单步执行事件循环的第一次迭代,它将调用迭代为零的
step
函数,然后注册两个处理程序,一个用于setImmediate
,一个用于process.nextTick
,然后我们从setImmediate
处理程序递归调用这个函数,该处理程序将在下一个检查阶段运行。nextTick
处理程序将在中断事件循环的当前操作结束时运行,因此即使它是第二个注册的,但实际上它将首先运行。顺序最终为:
nextTick
在当前操作结束、下一个事件循环开始、正常事件循环阶段执行时触发,setImmediate
触发并递归调用step
函数以重新启动整个过程。以上代码的输出为:
现在,让我们将对
step
的递归调用转移到nextTick
处理程序中,而不是setImmediate
。既然我们已经把对
step
的递归调用移到了nextTick
处理程序中,那么事情就会按照不同的顺序进行,我们的第一次事件循环迭代运行并调用step
,注册一个setImmedaite
处理程序和一个nextTick
处理程序。当前操作结束后,nextTick
处理程序将触发,递归调用step
并注册另一个setImmediate
处理程序以及另一个nextTick
处理程序。由于nextTick
处理程序在当前操作后触发,因此在nextTick
处理程序中注册nextTick
处理程序将导致第二个处理程序在当前处理程序操作完成后立即运行。nextTick
处理程序将继续触发,防止当前事件循环继续。我们将在看到单个setImmediate
处理程序激发之前完成所有nextTick
处理程序。以上代码的输出结果为:
请注意,如果我们没有中断递归调用并在10次迭代后中止它,那么
nextTick
调用将继续递归,永远不会让事件循环继续到下一阶段。这就是nextTick
在递归使用时可能阻塞的原因,而setImmediate
将在下一个事件循环中触发,并从一个won '中设置另一个setImmediate
处理程序。t根本不中断当前事件循环,允许其继续正常执行事件循环的阶段。希望能有所帮助!
PS-我同意其他评论者的观点,这两个函数的名称可以很容易地交换,因为
nextTick
听起来像是在下一个事件循环中触发,而不是在当前循环的结尾,而且当前循环的结尾比下一个循环的开头更"直接"。8zzbczxx4#
在答案的注解中,它没有明确指出nextTick从宏语义转移到了微语义。
在节点0.9之前(当引入setImmediate时),nextTick在下一调用栈的开始处操作。
从节点0.9开始,nextTick在现有调用堆栈的末尾操作,而setImmediate在下一个调用堆栈的开头
查看https://github.com/YuzuJS/setImmediate以获取工具和详细信息
cnh2zyt35#
这里有一些很好的答案,详细说明了它们是如何工作的。
只是添加一个回答特定问题的选项:
什么时候应该使用
nextTick
,什么时候应该使用setImmediate
?始终使用
setImmediate
。Node.js事件循环、计时器和
process.nextTick()
文档包括以下内容:setImmediate()
,因为它更容易推理(而且它会导致代码与更广泛的环境兼容,如浏览器JS)。*在文档的前面部分,它警告说
process.nextTick
可能导致...因为它允许您通过递归
process.nextTick()
调用来“饥饿”I/O,从而防止事件循环到达轮询阶段。事实证明,
process.nextTick
甚至可以饿死Promises
:另一方面,
setImmediate
“* 更容易推理 *”,并避免了以下类型的问题:因此,除非对
process.nextTick
的独特行为有特殊需要,否则推荐的方法是“* 在所有情况下都使用setImmediate()
*"。yrdbyhpb6#
简单地说,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
hpcdzsge7#
我建议你查看一下docs部分的循环,以获得更好的理解。一些片段取自那里:
我们有两个电话就用户而言是相似的,但他们的名字是混乱的。
事件循环
本质上,名称应该被交换。process.nextTick()比setImmediate()更快地触发,但这是过去的产物,不太可能改变。
lx0bsm1f8#
永远不要使用
process.nextTick()
中断CPU密集型操作你不应该使用process.nextTick()来分割这样的工作,这样做会导致微任务队列永远不会清空--你的应用程序将永远陷入同一个阶段! --Thomas Hunter. Distributed Systems with Node.js
一旦
process.nextTick()
击发,它将始终保持在相同相位。示例
在本例中,
setInterval()
表示应用程序执行的一些异步工作,例如响应传入的HTTP请求。一旦运行了
nt_recursive()
函数,应用程序将以一个永不清空的微任务队列结束,并且异步工作将永远不会得到处理。但是替代版本
si_recursive()
没有同样的副作用。在检查阶段内进行
setImmediate()
调用会将回调添加到 * next * 事件循环迭代的检查阶段队列,而不是当前阶段的队列。用例可能使用
process.nextTick
使函数处理全部异步。
在本例中,使用
setImmediate()
或process.nextTick()
都可以;只要确保不会意外地引入递归即可。