JavaScript execution mechanism and event loop in nodejs environment
This article brings you an introduction to the usage of JavaScript high-order functions. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
1. Description
nodejs is executed in a single thread, and it is based on an event-driven non-blocking IO programming model. This allows us to continue executing the code without waiting for the asynchronous operation result to return. When an asynchronous event is triggered, the main thread will be notified, and the main thread will execute the callback of the corresponding event.
This article explains the execution process of JavaScript code in node. The following is the test code. If you know the output result, then you don’t need to read this article. If you don’t know the output result, then this video The article can help you understand:
console.log(1) setTimeout(function () { new Promise(function (resolve) { console.log(2) resolve() }) .then(() => { console.log(3) }) }) setTimeout(function () { console.log(4) })
Complex:
setTimeout(() => { console.log('1') new Promise((resolve) => { console.log('2'); resolve(); }) .then(() => { console.log('3') }) new Promise((resolve)=> { console.log('4'); resolve()}) .then(() => { console.log('5') }) setTimeout(() => { console.log('6') setTimeout(() => { console.log('7') new Promise((resolve) => { console.log('8'); resolve() }) .then( () => { console.log('9') }) new Promise((resolve) => { console.log('10'); resolve() }) .then(() => { console.log('11') }) }) setTimeout(() => { console.log('12') }, 0) }) setTimeout(() => { console.log('13') }, 0) }) setTimeout(() => { console.log('14') }, 0) new Promise((resolve) => { console.log('15'); resolve() }) .then( ()=> { console.log('16') }) new Promise((resolve) => { console.log('17'); resolve() }) .then(() => { console.log('18') })
2. The startup process of nodejs
The node.js startup process can be divided into the following Steps:
- Call the platformInit method to initialize the nodejs running environment.
- Call the performance_node_start method to perform performance statistics on nodejs.
- Judgement of openssl settings.
- Call v8_platform.Initialize to initialize the libuv thread pool.
- Call V8::Initialize to initialize the V8 environment.
- Create a nodejs running instance.
- Start the instance created in the previous step.
- Start executing the js file. After the synchronization code is executed, enter the event loop.
- When there are no events to listen to, the nodejs instance is destroyed and the program execution is completed.
3. Detailed explanation of nodejs event loop
Nodejs subdivides the message loop into 6 stages (official Called Phase), each stage will have a queue-like structure that stores the callback functions that need to be processed in that stage.
Nodejs In order to prevent too many tasks in a certain stage from causing starvation in subsequent stages , so in each iteration of the message loop, there is a maximum number of callbacks executed in each stage. If the number is exceeded, the current stage will be forcibly ended and the next stage will be entered. This rule applies to every callback in the message loop. One stage.
3.1 Timer stage
This is the first stage of the message loop, using a for
loop to process all setTimeout
and setInterval
callbacks.
These callbacks are saved in a minimum heap (min heap). In this way, the engine only needs to judge the header element each time, and if it meets the conditions, it will be taken out and executed until it encounters a The Timer Phase ends only when the conditions are not met or the queue is empty.
The method to determine whether a certain callback meets the conditions in the Timer phase is also very simple. The message loop will save the current system time every time it enters the Timer. , and then just check whether the startup time set by the callback function in the above minimum heap exceeds the time saved when entering the Timer. If it exceeds, take it out and execute it.
3.2 Pending I/O Callback Phase
Execute almost all callbacks except close callbacks
, setTimeout()
, setInterval()
, setImmediate()
callbacks, for exampleTCP connection error
, fs.read
, socket
and other callback functions for IO operations, as well as callbacks for various errors.
3.3 Idle, Prepare phase
Some calls within the system.
3.4 Poll stage, important stage
This is the most important stage in the entire message cycle. Its function is to wait for asynchronous requests and data, because it supports the entire message cycle mechanism.
The poll phase has two main functions: one is to execute the callback of timers whose lower limit time has been reached, and the other is to process events in the poll queue.
Note: Many APIs of Node are based on event subscription, such as fs.readFile. These callbacks should be completed in the poll
stage.
When the event loop enters the poll phase:
-
#poll
When the queue is not empty, the event loop must first traverse the queue and execute the callback synchronously until the queue The number of cleared or executed callbacks reaches the system limit. -
poll
When the queue is empty, there are two situations.- If the code has been set with a callback by
setImmediate()
, then the event loop directly ends thepoll
stage and enters thecheck
stage. Execute the callback in thecheck
queue. -
If the code is not set
setImmediate()
Set callback:- If there are timers set, then the event loop will check the timers at this time. If one or more timers have reached the lower limit, then the event loop will wrap back to the timers stage and execute the effective callback of the timers. queue.
- If timers are not set, the event loop is blocked at this time Waiting in the poll phase for the event callback to be added to the poll queue.
- If the code has been set with a callback by
In the Poll phase, when none of the event callbacks registered by the js layer code returns, the event loop will temporarily block in the poll phase and unblock it. Conditions:
- When the poll phase is executed, a timeout timeout will be passed in, which is the maximum blocking time of the poll phase.
- When the timeout time has not expired, if an event returns, the callback function registered for the event will be executed. When the timeout timeout expires, the poll phase will exit and the next phase will be executed.
What is the appropriate setting for this timeout? The answer is the difference between the start time of the callback to be executed recently in the Timer Phase and the present. Assume that the difference is detal. Because there is nothing waiting to be executed after the Poll Phase. Callback. So the maximum waiting time here is delta. If an event wakes up the message loop during the period, then continue the work of the next Phase; if nothing happens during the period, then after timeout, the message loop still has to enter the subsequent Phase, so The Timer Phase of the next iteration can also be executed.
Nodejs drives the entire message loop through the Poll Phase, waiting for IO events and the arrival of kernel asynchronous events.
3.5 Check phase
This stage only handles the callback function of setImmediate.
So why is there a special stage to handle setImmediate? Simply put, it is because the Poll stage may set some callbacks and hope to run after the Poll stage . So the Check stage is added after the Poll stage.
3.6 Close Callbacks stage
Specializes in handling some close type callbacks. For example, socket.on('close', .. .)
. Used for resource cleaning.
4. Nodejs execution JS code process and event loop process
1. Node initialization
Initialize node environment
Execute the entered code
Executeprocess.nextTick
Callback
Execute microtasks
2. Enter the event loop
2.1. Entering the Timer
stage
- Check whether the
Timer
queue has an expiredTimer
callback. If so, Execute all expiredTimer
callbacks in ascending order byTimerId
- Check whether there are
process.nextTick
tasks, if so, execute them all - Check whether there are microtasks (promise), if so, execute them all
- Exit this stage
2.2, enter Pending I/O Callback
Phase
- Checks whether there is a callback for
Pending I/O Callback
, and if so, executes the callback. If you do not exit this stage - Check whether there are
process.nextTick
tasks, if so, execute them all - Check whether there are microtasks (promise) , if so, execute all
- Exit this stage
2.3. Enter idle, prepare
stage
This stage has little to do with JavaScript , skip
2.4 and enter the Poll
stage
First check whether there is an unfinished callback. If it exists, there are two situations:
The first case: there is an executable callback
Execute all available callbacks (including expired timers and some IO events, etc.)
Check whether there is process.nextTick
Tasks, if there are any, execute them all
Check whether there are microtasks (promise), if there are, execute them all
Exit this stage
Second type Situation: There is no executable callback
Check if there is an immediate
callback, if so, exit the Poll phase. If not, block in this stage, waiting for new event notification
If there is no unfinished callback, exit the Poll stage
2.5, entercheck
Phase
If there is an immediate callback, execute all immediate callbacks
Check whether there are process.nextTick
tasks, if so, execute them all
Check whether there are microtasks (promise), if so, execute them all
Exit this stage
2.6, enter the closing
stage
if If there is an immediate callback, execute all immediate callbacks
Check whether there are process.nextTick
tasks, if so, execute them all
Check whether there are microtasks (promise), if Yes, execute all
Exit this stage
3. Check whether there are active handles (timer, IO and other event handles)
If there are , continue the next round of event loop
If not, end the event loop and exit the program
Note:
Each sub-stage of the event loop will execute the following process in sequence before exiting:
Check whether there is a process.nextTick callback, and if so, execute them all.
Check whether there are microtasks (promise), and if so, execute them all.
4.1 关于Promise和process.nextTick
事件循环队列先保证所有的process.nextTick
回调,然后将所有的Promise
回调追加在后面,最终在每个阶段结束的时候一次性拿出来执行。
此外,process.nextTick
和Promise
回调的数量是受限制的,也就是说,如果一直往这个队列中加入回调,那么整个事件循环就会被卡住
。
4.2 关于setTimeout(…, 0) 和 setImmediate
这两个方法的回调到底谁快?
如下面的例子:
setImmediate(() => console.log(2)) setTimeout(() => console.log(1))
使用nodejs多次执行后,发现输出结果有时是1 2
,有时是2 1
。
对于多次执行输出结果不同,需要了解事件循环的基础问题。
首先,Nodejs启动,初始化环境后加载我们的JS代码(index.js).发生了两件事(此时尚未进入消息循环环节):
setImmediate 向 Check 阶段 中添加了回调 console.log(2);setTimeout 向 Timer 阶段 中添加了回调 console.log(1)
这时候, 要初始化阶段完毕, 要进入 Nodejs 消息循环了。
为什么会有两种输出呢? 接下来一步很关键:
当执行到 Timer 阶段 时, 会发生两种可能. 因为每一轮迭代刚刚进入 Timer 阶段 时会取系统时间保存起来, 以 ms(毫秒) 为最小单位.
如果 Timer 阶段 中回调预设的时间 > 消息循环所保存的时间, 则执行 Timer 阶段 中的该回调. 这种情况下先输出 1, 直到 Check 阶段 执行后,输出2.总的来说, 结果是 1 2.
如果运行比较快, Timer 阶段 中回调预设的时间可能刚好等于消息循环所保存的时间, 这种情况下, Timer 阶段 中的回调得不到执行, 则继续下一个 阶段. 直到 Check 阶段, 输出 2. 然后等下一轮迭代的 Timer 阶段, 这时的时间一定是满足 Timer 阶段 中回调预设的时间 > 消息循环所保存的时间 , 所以 console.log(1) 得到执行, 输出 1. 总的来说, 结果就是 2 1.
所以, 输出不稳定的原因就取决于进入 Timer 阶段 的时间是否和执行 setTimeout 的时间在 1ms 内. 如果把代码改成如下, 则一定会得到稳定的输出:
require('fs').readFile('my-file-path.txt', () => { setImmediate(() => console.log(2)) setTimeout(() => console.log(1)) });
这是因为消息循环在 Pneding I/O Phase
才向 Timer 和 Check 队列插入回调. 这时按照消息循环的执行顺序, Check 一定在 Timer 之前执行。
从性能角度讲, setTimeout 的处理是在 Timer Phase, 其中 min heap 保存了 timer 的回调, 因此每执行一个回调的同时都会涉及到堆调整. 而 setImmediate 仅仅是清空一个队列. 效率自然会高很多.
再从执行时机上讲. setTimeout(..., 0) 和 setImmediate 完全属于两个阶段.
5. 一个实际例子演示
下面以一段代码来说明nodejs运行JavaScript的机制。
如下面一段代码:
setTimeout(() => { // settimeout1 console.log('1') new Promise((resolve) => { console.log('2'); resolve(); }) // Promise3 .then(() => { console.log('3') }) new Promise((resolve)=> { console.log('4'); resolve()}) // Promise4 .then(() => { console.log('5') }) setTimeout(() => { // settimeout3 console.log('6') setTimeout(() => { // settimeout5 console.log('7') new Promise((resolve) => { console.log('8'); resolve() }) // Promise5 .then( () => { console.log('9') }) new Promise((resolve) => { console.log('10'); resolve() }) // Promise6 .then(() => { console.log('11') }) }) setTimeout(() => { console.log('12') }, 0) // settimeout6 }) setTimeout(() => { console.log('13') }, 0) // settimeout4 }) setTimeout(() => { console.log('14') }, 0) // settimeout2 new Promise((resolve) => { console.log('15'); resolve() }) // Promise1 .then( ()=> { console.log('16') }) new Promise((resolve) => { console.log('17'); resolve() }) // Promise2 .then(() => { console.log('18') })
上面代码执行过程:
node初始化
执行JavaScript代码
遇到setTimeout
, 把回调函数放到Timer
队列中,记为settimeout1
遇到setTimeout
, 把回调函数放到Timer
队列中,记为settimeout2
遇到Promise
,执行,输出15,把回调函数放到微任务
队列,记为Promise1
遇到Promise
,执行,输出17,把回调函数放到微任务
队列,记为Promise2
代码执行结束,此阶段输出结果:15 17
没有process.nextTick
回调,略过
执行微任务
检查微任务队列是否有可执行回调,此时队列有2个回调:Promise1、Promise2
执行Promise1回调,输出16
执行Promise2回调,输出18
此阶段输出结果:16 18
进入第一次事件循环
进入Timer阶段
检查Timer队列是否有可执行的回调,此时队列有2个回调:settimeout1、settimeout2
执行settimeout1回调:
输出1、2、4
添加了2个微任务,记为Promise3、Promise4
添加了2个Timer任务,记为settimeout3、settimeout4
执行settimeout2回调,输出14
Timer队列任务执行完毕
没有process.nextTick
回调,略过
检查微任务队列是否有可执行回调,此时队列有2个回调:Promise3、Promise4
按顺序执行2个微任务,输出3、5
此阶段输出结果:1 2 4 14 3 5
Pending I/O Callback阶段没有任务,略过
进入 Poll 阶段
检查是否存在尚未完成的回调,此时有2个回调:settimeout3、settimeout4
Execute settimeout3 callback
Output 6
Added 2 Timer tasks, recorded as settimeout5, settimeout6
Execute settimeout4 callback, output 13
There is no process.nextTick
callback, skip
There is no microtask, skip
The output result of this stage: 6 13
There are no tasks in the check and closing phases, skip them
Check whether there are still active handles (timers, IO and other event handles)
, yes, continue to the next round of event loop
Enter the second event loop
Enter the Timer phase
Check whether the Timer queue has an executable callback, this The queue has 2 callbacks: settimeout5, settimeout6
Execute settimeout5 callback:
Output 7, 8, 10
Added 2 microtasks , recorded as Promise5, Promise6
executes the settimeout6 callback, outputs 12
There is no process.nextTick
callback, skip
Check whether the microtask queue has executable callbacks. At this time, the queue has 2 callbacks: Promise5, Promise6
Execute 2 microtasks in order, output 9, 11
Output results of this stage: 7 8 10 12 9 11
There are no tasks in the Pending I/O Callback, Poll, check, and closing phases, so skip them
Check if there are still active handles (timer, IO and other event handles)
, if there are no more, end the event loop and exit the program
End of program execution , output result: 15 17 16 18 1 2 4 14 3 5 6 13 7 8 10 12 9 11
[Related recommendations: JavaScript video tutorial】
The above is the detailed content of JavaScript execution mechanism and event loop in nodejs environment. For more information, please follow other related articles on the PHP Chinese website!

The main difference between Python and JavaScript is the type system and application scenarios. 1. Python uses dynamic types, suitable for scientific computing and data analysis. 2. JavaScript adopts weak types and is widely used in front-end and full-stack development. The two have their own advantages in asynchronous programming and performance optimization, and should be decided according to project requirements when choosing.

Whether to choose Python or JavaScript depends on the project type: 1) Choose Python for data science and automation tasks; 2) Choose JavaScript for front-end and full-stack development. Python is favored for its powerful library in data processing and automation, while JavaScript is indispensable for its advantages in web interaction and full-stack development.

Python and JavaScript each have their own advantages, and the choice depends on project needs and personal preferences. 1. Python is easy to learn, with concise syntax, suitable for data science and back-end development, but has a slow execution speed. 2. JavaScript is everywhere in front-end development and has strong asynchronous programming capabilities. Node.js makes it suitable for full-stack development, but the syntax may be complex and error-prone.

JavaScriptisnotbuiltonCorC ;it'saninterpretedlanguagethatrunsonenginesoftenwritteninC .1)JavaScriptwasdesignedasalightweight,interpretedlanguageforwebbrowsers.2)EnginesevolvedfromsimpleinterpreterstoJITcompilers,typicallyinC ,improvingperformance.

JavaScript can be used for front-end and back-end development. The front-end enhances the user experience through DOM operations, and the back-end handles server tasks through Node.js. 1. Front-end example: Change the content of the web page text. 2. Backend example: Create a Node.js server.

Choosing Python or JavaScript should be based on career development, learning curve and ecosystem: 1) Career development: Python is suitable for data science and back-end development, while JavaScript is suitable for front-end and full-stack development. 2) Learning curve: Python syntax is concise and suitable for beginners; JavaScript syntax is flexible. 3) Ecosystem: Python has rich scientific computing libraries, and JavaScript has a powerful front-end framework.

The power of the JavaScript framework lies in simplifying development, improving user experience and application performance. When choosing a framework, consider: 1. Project size and complexity, 2. Team experience, 3. Ecosystem and community support.

Introduction I know you may find it strange, what exactly does JavaScript, C and browser have to do? They seem to be unrelated, but in fact, they play a very important role in modern web development. Today we will discuss the close connection between these three. Through this article, you will learn how JavaScript runs in the browser, the role of C in the browser engine, and how they work together to drive rendering and interaction of web pages. We all know the relationship between JavaScript and browser. JavaScript is the core language of front-end development. It runs directly in the browser, making web pages vivid and interesting. Have you ever wondered why JavaScr


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

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

SublimeText3 Chinese version
Chinese version, very easy to use

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

WebStorm Mac version
Useful JavaScript development tools

Atom editor mac version download
The most popular open source editor
