An in-depth analysis of the microtask queue in the Node event loop
In previous articles, we learned that the event loop is a key part of Node.js, used to coordinate the execution of synchronous and asynchronous code.
It consists of six different queues. A nextTick queue and a Promise queue (called a microtask queue), a timer queue, an I/O queue, a check queue, and finally the shutdown queue. [Related tutorial recommendations: nodejs video tutorial, Programming teaching]
In each loop, the callback function will be dequeued (dequeued) at the appropriate time and called executed on the stack. Starting from this article, we'll run some experiments to make sure our understanding of the event loop is correct.
Our first set of experiments will focus on the nextTick queue and the Promise queue. But before we dive into the experiment, we need to understand how to queue callback functions.
Note: All experiments were conducted using the CommonJS module format.
Enqueue callback function
To add the callback function to the nextTick queue, we can use the built-in process.nextTick()
method. The syntax is very simple: process.nextTick(callbackFn)
. When the method is executed on the call stack, the callback function will be added to the nextTick queue.
To add the callback function to the Promise queue, we need to use Promise.resolve().then(callbackFn)
. When the Promise resolves, the callback function passed to then()
will be enqueued into the Promise queue.
Now that we know how to add callback functions to two queues, let's start our first experiment.
Experiment 1
Code
// index.js console.log("console.log 1"); process.nextTick(() => console.log("this is process.nextTick 1")); console.log("console.log 2");
This code records three different statements. The second statement uses process.nextTick()
to enqueue the callback function into the nextTick queue.
Visualization
The first console.log()
statement is pushed into the call stack for execution . It logs the appropriate message in the console and then pops the stack.
Next, execute process.nextTick()
on the call stack, enqueue the callback function into the nextTick queue, and pop it up. There is still user-written code that needs to be executed at this point, so the callback function must wait its turn.
Execution continues, the last console.log()
statement is pushed onto the stack, the message is logged in the console, and the function is popped off the call stack. Now, there is no more user-written synchronous code to execute, so control goes into the event loop.
The callback function in the nextTick queue is pushed into the call stack, console.log()
is pushed into the call stack and executed, and the corresponding message is recorded on the console.
console.log 1 console.log 2 this is process.nextTick 1
Corollary
All user-written synchronous JavaScript code executes before asynchronous code.
Let's move on to the second experiment.
Experiment 2
Code
// index.js Promise.resolve().then(() => console.log("this is Promise.resolve 1")); process.nextTick(() => console.log("this is process.nextTick 1"));
We have a Promise.resolve().then() call and a process.nextTick() call.
Visualization
#When the call stack executes line 1, it queues the callback function into the Promise queue; when the call stack When line 2 is executed, it queues the callback function into the nextTick queue.
No code needs to be executed after line 2.
Control goes into the event loop, where the nextTick queue takes precedence over the Promise queue (this is how the Node.js runtime works).
The event loop executes the nextTick queue callback function, and then executes the Promise queue callback function.
The console displays "this is process.nextTick 1", then "this is Promise.resolve 1".
this is process.nextTick 1 this is Promise.resolve 1
Inference
All callback functions in the nextTick queue are executed prior to callback functions in the Promise queue.
Let me walk you through a more detailed version of the second experiment above.
welfare experiment
code
// index.js process.nextTick(() => console.log("this is process.nextTick 1")); process.nextTick(() => { console.log("this is process.nextTick 2"); process.nextTick(() => console.log("this is the inner next tick inside next tick") ); }); process.nextTick(() => console.log("this is process.nextTick 3")); Promise.resolve().then(() => console.log("this is Promise.resolve 1")); Promise.resolve().then(() => { console.log("this is Promise.resolve 2"); process.nextTick(() => console.log("this is the inner next tick inside Promise then block") ); }); Promise.resolve().then(() => console.log("this is Promise.resolve 3"));
This code contains three process.nextTick()
call and three Promise.resolve()
call statements. Each callback function logs the appropriate message.
但是,第二个 process.nextTick()
和第二个 Promise.resolve()
都有一个额外的 process.nextTick()
语句,每个都带有一个回调函数。
可视化
为了加快对此可视化的解释,我将省略调用栈讲解。当调用栈执行所有 6 个语句时,nextTick 队列中有 3 个回调函数,Promise 队列中也有 3 个回调函数。没有其他要执行的内容后,控制权进入事件循环。
我们知道,nextTick 队列中具有高优先级。首先执行第 1 个回调函数,并将相应的消息记录到控制台中。
接下来,执行第 2 个回调函数,记录了第 2 条日志语句。但是,这个回调函数包含另一个对 process.nextTick()
的调用,该方法内的回调函数(译注:即() => console.log("this is the inner next tick inside next tick")
)入队到nextTick 队列末尾。
然后 Node.js 执行第 3 个回调函数并将相应消息记录到控制台上。最初只有 3 个回调,但是因为第 2 次时向nextTick 队列又添加了一个,所以变成 4 个了。
事件循环将第 4 个回调函数推入调用栈,执行 console.log()
语句。
接着处理完 nextTick 队列之后,控制流程进入到 Promise 队列。Promise 队列与 nextTick 队列处理方式类似。
首先记录“Promise.resolve 1”,然后是“Promise.resolve 2”,这时因为调用 process.nextTick() 的原因,一个函数(译注:即 () => console.log("this is the inner next tick inside Promise then block")
) 被推入 nextTick 队列了。尽管如此,控制流程仍停留在 Promise 队列,因此还会继续执行队列中的其他函数。然后我们得到“Promise.resolve 3”,此时 Promise 队列为空。
Node.js 将再次检查微任务队列中是否有新的回调。由于 nextTick 队列中有一个回调,因此会执行这个回调,导致我们的最后一条日志输出。
this is process.nextTick 1 this is process.nextTick 2 this is process.nextTick 3 this is the inner next tick inside next tick this is Promise.resolve 1 this is Promise.resolve 2 this is Promise.resolve 3 this is the inner next tick inside Promise then block
这可能是一个稍微高级的实验,但推论仍然相同。
推论
nextTick 队列中的所有回调函数优先于 Promise 队列中的回调函数执行。
使用 process.nextTick()
时要小心。过度使用此方法可能会导致事件循环饥饿,从而阻止队列中的其余部分运行。当存在大量的 nextTick() 调用时,I/O 队列是无法执行自己的回调函数的。官方文档建议使用 process.nextTick()
的两个主要场景:处理错误或在调用栈为空事件循环继续之前执行回调用。所以在使用 process.nextTick()
时,要明智一些。
总结
实验表明,用户编写的所有同步 JavaScript 代码优先于异步代码执行,并且 nextTick 队列中的所有回调函数优先于 Promise 队列中的回调函数执行。
原文链接:Visualizing nextTick and Promise Queues in Node.js Event Loop,2023年3月30日,by Vishwas Gopinath
更多node相关知识,请访问:nodejs 教程!
The above is the detailed content of An in-depth analysis of the microtask queue in the Node event loop. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



PHP and Vue: a perfect pairing of front-end development tools. In today's era of rapid development of the Internet, front-end development has become increasingly important. As users have higher and higher requirements for the experience of websites and applications, front-end developers need to use more efficient and flexible tools to create responsive and interactive interfaces. As two important technologies in the field of front-end development, PHP and Vue.js can be regarded as perfect tools when paired together. This article will explore the combination of PHP and Vue, as well as detailed code examples to help readers better understand and apply these two

In front-end development interviews, common questions cover a wide range of topics, including HTML/CSS basics, JavaScript basics, frameworks and libraries, project experience, algorithms and data structures, performance optimization, cross-domain requests, front-end engineering, design patterns, and new technologies and trends. . Interviewer questions are designed to assess the candidate's technical skills, project experience, and understanding of industry trends. Therefore, candidates should be fully prepared in these areas to demonstrate their abilities and expertise.

JavaScript tutorial: How to get HTTP status code, specific code examples are required. Preface: In web development, data interaction with the server is often involved. When communicating with the server, we often need to obtain the returned HTTP status code to determine whether the operation is successful, and perform corresponding processing based on different status codes. This article will teach you how to use JavaScript to obtain HTTP status codes and provide some practical code examples. Using XMLHttpRequest

Django is a web application framework written in Python that emphasizes rapid development and clean methods. Although Django is a web framework, to answer the question whether Django is a front-end or a back-end, you need to have a deep understanding of the concepts of front-end and back-end. The front end refers to the interface that users directly interact with, and the back end refers to server-side programs. They interact with data through the HTTP protocol. When the front-end and back-end are separated, the front-end and back-end programs can be developed independently to implement business logic and interactive effects respectively, and data exchange.

As a fast and efficient programming language, Go language is widely popular in the field of back-end development. However, few people associate Go language with front-end development. In fact, using Go language for front-end development can not only improve efficiency, but also bring new horizons to developers. This article will explore the possibility of using the Go language for front-end development and provide specific code examples to help readers better understand this area. In traditional front-end development, JavaScript, HTML, and CSS are often used to build user interfaces

Django: A magical framework that can handle both front-end and back-end development! Django is an efficient and scalable web application framework. It is able to support multiple web development models, including MVC and MTV, and can easily develop high-quality web applications. Django not only supports back-end development, but can also quickly build front-end interfaces and achieve flexible view display through template language. Django combines front-end development and back-end development into a seamless integration, so developers don’t have to specialize in learning

Combination of Golang and front-end technology: To explore how Golang plays a role in the front-end field, specific code examples are needed. With the rapid development of the Internet and mobile applications, front-end technology has become increasingly important. In this field, Golang, as a powerful back-end programming language, can also play an important role. This article will explore how Golang is combined with front-end technology and demonstrate its potential in the front-end field through specific code examples. The role of Golang in the front-end field is as an efficient, concise and easy-to-learn

Introduction to the method of obtaining HTTP status code in JavaScript: In front-end development, we often need to deal with the interaction with the back-end interface, and HTTP status code is a very important part of it. Understanding and obtaining HTTP status codes helps us better handle the data returned by the interface. This article will introduce how to use JavaScript to obtain HTTP status codes and provide specific code examples. 1. What is HTTP status code? HTTP status code means that when the browser initiates a request to the server, the service
