问题描述
我已经阅读了有关process.nextTick()的官方文档和许多其他博客,但是在某些主题上我有些困惑。
首先,编写过程process.nextTick()中的回调是在下一次迭代开始之前执行的。
第二,在I / O周期内,事件循环当前处于轮询阶段。在轮询阶段之后,事件循环进入检查阶段,在该阶段执行setImmediate方法中调用的所有回调。
现在在以下代码中
const fs = require('fs');
function main() {
fs.readFile('./xy.txt',function(err,buff){
setTimeout(()=> console.log("timeout inside fs"),0);
setImmediate(()=> console.log("immediate inside fs"));
process.nextTick(()=>{console.log("process.nextTick")});
console.log("inside fs");
})
console.log("called inside main fn in first-iteration);
}
main();
console.log("called in first-iteration);
输出为:
called inside main fn in first-iteration
called in first iteration
在此期间,将注册fs fn的回调,并且将对以上两行进行控制台,因为运行入口脚本时不会发生事件循环。现在,事件循环的第一个迭代将从定时器阶段开始,因为不存在任何定时器,它将移至挂起阶段,然后移至轮询阶段,其中存在一个回调(fs fn回调),事件循环开始执行fs回调,现在将注册setTimeout回调和setImmediate回调。在该过程之后,nextTick回调将被注册在nextTickQueue中,该队列将在下一次迭代或滴答(第二次迭代)中执行。现在,轮询阶段结束后,我们在第三行上显示了inside fs
。
接下来,事件循环应移至检查阶段,在该阶段存在setImmediate回调,并应控制台immediate inside fs
,随后事件循环应移至下一阶段,并且第一次迭代应结束。在开始第二次迭代之前,应先对process.nextTick
进行控制台,然后最后对timeout inside fs
进行控制台。
因此使最终输出为:
called inside main fn in first-iteration
called in first iteration
inside fs
immediate inside fs
process.nextTick
timeout inside fs
但是输出结果是:
called inside main fn in first-iteration
called in first iteration
inside fs
process.nextTick
immediate inside fs
timeout inside fs
在某处写道,微任务(process.nextTick)优先执行,因此事件循环将保留所有执行并乍一看执行微任务。但是,如果也是这种情况,为什么在inside fs
之前安慰process.nextTick
?
基本上,我很困惑,process.nextTick()和事件循环流程如何进行?
如果需要进一步澄清问题,请提前在评论中提及。
解决方法
节点开发人员中的一大误解是 process.nextTick在以下tick(迭代)中运行代码
在回答您的问题之前,我先告诉您一些事情:
# config/routes.rb
Rails.application.routes.draw do
# ...
devise_for :users,controllers: {
sessions: 'users/sessions'
}
# ...
end
从技术上讲不是事件循环的一部分。相反,无论事件循环的当前阶段如何,都将在当前操作完成之后处理nextTickQueue.next tick队列与其他四个主队列分开显示,因为它不是libuv本身提供的,而是在Node中实现的
在事件循环的每个阶段(计时器队列,IO事件队列,即时队列,关闭处理程序队列是四个主要阶段)之前,进入该阶段之前,Node会检查nextTick队列是否有任何排队的事件。如果队列不为空,则Node将立即开始处理队列,直到队列为空,然后再移至下一阶段的事件循环。
Node v11中引入了一些更改,这些更改大大改变了 nextTick的执行顺序,Promise回调, 从Node v11开始的setImmediate和setTimeout回调。
nextTikcs和promise回调队列在每个计时器和立即回调之间进行处理,无论其他超时回调和 即时的回调已经存在于相应的队列中。
在nodejs11和nodejs11及更高版本之前运行此https://repl.it/@sandeepp2016/processNextTick#index.js,您将看到区别 按执行顺序。
除了调用process.nextTick()
以及在Nodejs中如何执行同步和非同步代码外,您几乎可以正确地理解流程。
当事件循环进入轮询阶段时,它将执行nextTick
回调队列,并排入io事件队列。由于队列中没有其他io事件回调,因此事件循环将进入检查阶段,但是在运行检查阶段的回调之前,它将执行所有fs.read
和promise任务队列。这就是为什么要在您的情况下打印nexttikcs
,然后process.nexttick
进行检查的原因,它将在检查阶段返回到计时器阶段并打印immediate inside fs
最后一个问题,当程序在timeout inside fs.
函数中输入时,前三个调用是异步的,前两个调用将排队进入事件循环。但是main
将立即放入调用堆栈,并由Nodejs主踏板执行。 console.log("inside fs")
也将异步执行(不是libuv事件循环的一部分),但是在轮询阶段之后和检查阶段之前(如图中所示)。因此它将在process.next
之前打印inside fs
。
请记住,事件循环只处理异步代码,同步代码直接在主线程中执行而没有事件循环。
有关更多详细信息,请阅读
https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/