何时在nodejs事件循环中调用process.nextTiick?

问题描述

我已经阅读了有关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(迭代)中运行代码

在回答您的问题之前,我先告诉您一些事情:

enter image description here

# 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将立即开始处理队列,直到队列为空,然后再移至下一阶段的事件循环。

  1. Node v11中引入了一些更改,这些更改大大改变了 nextTick的执行顺序,Promise回调, 从Node v11开始的setImmediate和setTimeout回调。

  2. nextTikcs和promise回调队列在每个计时器和立即回调之间进行处理,无论其他超时回调和 即时的回调已经存在于相应的队列中。

  3. 在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://blog.insiderattack.net/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-9226cbe7a6aa

https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...