The content of this article is about analyzing the event loop mechanism of Node.js. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
The event loop mechanism and some related concepts have been introduced in detail in the browser article, but it is mainly for research on the browser side. Is the same for the Node environment? Let’s take a look at a demo first:
setTimeout(()=>{ console.log('timer1') Promise.resolve().then(function() { console.log('promise1') })}, 0)setTimeout(()=>{ console.log('timer2') Promise.resolve().then(function() { console.log('promise2') })}, 0)
Compile and run it with the naked eye. The result in the browser is as follows. You already know the truth, so I won’t go into details here.
timer1 promise1 timer2 promise2
Then execute it under Node, eh. . . Strange, the running result is different from the browser~
timer1 timer2 promise1 promise2
The example shows that the event loop mechanism of the browser and Node.js is different, let’s take a look~
Event processing of Node.js
Node.js uses V8 as the parsing engine of js, and uses its own designed libuv for I/O processing. libuv is an event-driven cross-platform abstraction layer that encapsulates Some underlying features of different operating systems provide a unified API to the outside world. The event loop mechanism is also implemented in it. Core source code reference:
int uv_run(uv_loop_t* loop, uv_run_mode mode) { int timeout; int r; int ran_pending; r = uv__loop_alive(loop); if (!r) uv__update_time(loop); while (r != 0 && loop->stop_flag == 0) { uv__update_time(loop); // timers阶段 uv__run_timers(loop); // I/O callbacks阶段 ran_pending = uv__run_pending(loop); // idle阶段 uv__run_idle(loop); // prepare阶段 uv__run_prepare(loop); timeout = 0; if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); // poll阶段 uv__io_poll(loop, timeout); // check阶段 uv__run_check(loop); // close callbacks阶段 uv__run_closing_handles(loop); if (mode == UV_RUN_ONCE) { uv__update_time(loop); uv__run_timers(loop); } r = uv__loop_alive(loop); if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT) break; } if (loop->stop_flag != 0) loop->stop_flag = 0; return r; }
According to the official introduction of Node.js, each event loop contains 6 stages. , corresponding to the implementation in the libuv source code, as shown in the figure below
timers stage: This stage executes the callback of timer (setTimeout, setInterval)
I/ O callbacks phase: Execute some system call errors, such as network communication error callback
idle, prepare phase: Only used internally by node
poll phase: Get new I/O events, appropriate Under the conditions, the node will be blocked here
check stage: execute the callback of setImmediate()
close callbacks stage: execute the close event callback of the socket
We focus on timers and poll , Just check these three stages, because most asynchronous tasks in daily development are processed in these three stages.
timers phase
timers is the first phase of the event loop, Node Will check whether there is an expired timer, and if so, push its callback into the timer's task queue to wait for execution. In fact, Node There is no guarantee that the timer will be executed immediately when the preset time is reached, because Node's expiration check of the timer is not necessarily reliable. It will be affected by other running programs on the machine, or the main thread is not idle at that time. For example, in the following code, the execution order of setTimeout() and setImmediate() is uncertain.
setTimeout(() => { console.log('timeout') }, 0) setImmediate(() => { console.log('immediate') })
But if you put them in an I/O callback, setImmediate() must be executed first, because the poll phase is followed by the check phase.
poll phase
The poll phase mainly has two functions:
Processing events in the poll queue
When there is a timer that has timed out, execute its callback Function
even loop will synchronously execute the callbacks in the poll queue until the queue is empty or the executed callbacks reach the system upper limit (the upper limit is unknown), then the even loop will check whether there is a preset setImmediate( ), divided into two situations:
If there is a preset setImmediate(), the event loop will end the poll phase and enter the check phase, and execute the task queue of the check phase
If there is no preset setImmediate(), the event loop will block and wait at this stage
Note one detail, no setImmediate() will cause an event The loop is blocked in the poll phase, so wouldn't the previously set timer not be able to be executed? So, in the poll phase event The loop will have a checking mechanism to check whether the timer queue is empty. If the timer queue is not empty, the event loop starts the next round of event loop, that is, re-enters the timer phase.
check phase
The callback of setImmediate() will be added to the check queue. From the event loop phase diagram, we can know that the execution order of the check phase is after the poll phase.
Summary
Each stage of the event loop has a task queue
When the event loop reaches a certain stage, the task queue of that stage will be executed until the queue is cleared. Or the executed callback reaches the system upper limit before it will move to the next stage
When all stages are executed sequentially once, the event loop is said to have completed a tick
It makes sense. But without the demo, I still don’t understand it completely. I’m anxious, now!
const fs = require('fs')fs.readFile('test.txt', () => { console.log('readFile') setTimeout(() => { console.log('timeout') }, 0) setImmediate(() => { console.log('immediate') }) })
There should be no doubt about the execution results
readFile immediate timeout
Differences between Node.js and the browser’s Event Loop
Recall the previous article, microtask tasks in the browser environment The queue is executed after each macrotask is executed.
In Node.js, microtask will be executed between various stages of the event loop. That is, after a stage is executed, the tasks in the microtask queue will be executed.
demo review
Review the demo at the beginning of the article, the global script (main()) is executed, and the two timers are sequentially Put it into the timer queue, main() is executed, the call stack is idle, and the task queue starts executing;
首先进入timers阶段,执行timer1的回调函数,打印timer1,并将promise1.then回调放入microtask队列,同样的步骤执行timer2,打印timer2;
至此,timer阶段执行结束,event loop进入下一个阶段之前,执行microtask队列的所有任务,依次打印promise1、promise2。
对比浏览器端的处理过程:
process.nextTick() VS setImmediate()
In essence, the names should be swapped. process.nextTick() fires more immediately than setImmediate()
来自官方文档有意思的一句话,从语义角度看,setImmediate() 应该比 process.nextTick() 先执行才对,而事实相反,命名是历史原因也很难再变。
process.nextTick() 会在各个事件阶段之间执行,一旦执行,要直到nextTick队列被清空,才会进入到下一个事件阶段,所以如果递归调用 process.nextTick(),会导致出现I/O starving(饥饿)的问题,比如下面例子的readFile已经完成,但它的回调一直无法执行:
const fs = require('fs')const starttime = Date.now()let endtime fs.readFile('text.txt', () => { endtime = Date.now() console.log('finish reading time: ', endtime - starttime)})let index = 0function handler () { if (index++ >= 1000) return console.log(`nextTick ${index}`) process.nextTick(handler) // console.log(`setImmediate ${index}`) // setImmediate(handler)}handler()
process.nextTick()的运行结果:
nextTick 1 nextTick 2 ...... nextTick 999 nextTick 1000 finish reading time: 170
替换成setImmediate(),运行结果:
setImmediate 1 setImmediate 2 finish reading time: 80 ...... setImmediate 999 setImmediate 1000
这是因为嵌套调用的 setImmediate() 回调,被排到了下一次event loop才执行,所以不会出现阻塞。
总结
1、Node.js 的事件循环分为6个阶段
2、浏览器和Node 环境下,microtask 任务队列的执行时机不同
Node.js中,microtask 在事件循环的各个阶段之间执行
浏览器端,microtask 在事件循环的 macrotask 执行完之后执行
3、递归的调用process.nextTick()会导致I/O starving,官方推荐使用setImmediate()
The above is the detailed content of Analyzing the event loop mechanism of Node.js. For more information, please follow other related articles on the PHP Chinese website!

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.


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

SublimeText3 Chinese version
Chinese version, very easy to use

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

WebStorm Mac version
Useful JavaScript development tools

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment