Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the mechanism of the event loop in Node.js

2025-03-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article introduces the relevant knowledge of "what is the mechanism of the event cycle in Node.js". Many people will encounter this dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Let's take a look at a demo:

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 with the naked eye, anthracene, the result in the browser is the following, the reason is understood, do not repeat.

Timer1promise1timer2promise2

Well, let's have a look at the execution under Node, hey. Strange, the result is not the same as that of the browser.

Timer1timer2promise1promise2

The example shows that the event loop mechanism of browser and Node.js is different. Let's take a look at it.

Event handling of Node.js

Node.js uses V8 as the parsing engine of js, while libuv,libuv, which is designed by ourselves, is a cross-platform abstraction layer based on event-driven, which encapsulates some underlying features of different operating systems and provides a unified API. The event loop mechanism is also implemented in it. The core source code is referenced:

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 phase uv__run_timers (loop) / / I callbacks stage ran_pending = uv__run_pending (loop); / / idle phase uv__run_idle (loop); / / prepare phase uv__run_prepare (loop); timeout = 0; if ((mode = = UV_RUN_ONCE & &! ran_pending) | | mode = = UV_RUN_DEFAULT) timeout = uv_backend_timeout (loop) / / poll phase uv__io_poll (loop, timeout); / / check phase uv__run_check (loop); / / close callbacks phase 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 Node.js, each event loop contains six phases, corresponding to the implementation in the libuv source code, as shown in the following figure

Timers phase: this phase executes the callback of timer (setTimeout, setInterval)

I am O callbacks phase: perform some system call errors, such as error callbacks for network traffic

Idle, prepare phase: for internal use only in node

Poll phase: get a new Ithumb O event, where node will block under appropriate conditions

Check phase: execute the callback of setImmediate ()

Close callbacks phase: execute close event callback of socket

Let's focus on timers, poll, and check, because most of the asynchronous tasks in daily development are handled in these three phases.

Timers stage

Timers is the first stage of the event cycle. Node will check for expired timer, and if so, press its callback into timer's task queue for execution. In fact, Node does not guarantee that timer will be executed immediately at the preset time, because Node's expiration check for timer may not be reliable, it will be affected by other running programs on the machine, or the main thread at that point in time will not be idle. 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 Iamp O callback, setImmediate () must be executed first, because the poll phase is followed by the check phase.

Poll stage

The poll phase has two main functions:

Handling events for poll queues

When there is a timed-out timer, execute its callback function

Even loop will synchronously execute the callback in the poll queue until the queue is empty or the callback reaches the system limit (the exact upper limit is unknown). Then even loop will check whether there is a default setImmediate (), which can be divided into two situations:

If there is a default setImmediate (), 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 (), event loop will block waiting at this stage

Note one detail: the absence of setImmediate () causes event loop to block during the poll phase, so the previously set timer cannot be executed. So, in the poll phase, event loop will have a check mechanism to check whether the timer queue is empty, and if the timer queue is not empty, event loop will start the next round of event cycles, that is, re-enter the timer phase.

Check stage

The callback of setImmediate () is added to the check queue, and as you can see from the phase diagram of event loop, the execution order of the check phase is after the poll phase.

Summary

Each phase of event loop has a task queue

When event loop reaches a certain stage, the task queue of that stage will be executed and will not move on to the next phase until the queue is empty or the callback reaches the system limit.

When all phases are executed sequentially once, event loop is said to have completed a tick

It makes sense, but I still don't understand completely without demo. Hold on, 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 implementation results.

ReadFileimmediatetimeout

Event Loop difference between Node.js and browser

In the browser environment, the task queue of microtask is executed after each macrotask is executed.

In Node.js, microtask executes between phases of the event cycle, that is, when a phase is completed, it executes the tasks of the microtask queue.

Demo Review

Review the demo at the beginning of the article, the global script (main ()) is executed, the two timer are put into the timer queue in turn, the main () execution is finished, the call stack is idle, and the task queue starts execution.

First, enter the timers phase, execute the callback function of timer1, print the timer1, and put the promise1.then callback into the microtask queue. In the same step, execute timer2 and print the timer2.

At this point, the execution of the timer phase is over, and before event loop moves on to the next phase, all the tasks of the microtask queue are executed, printing promise1 and promise2 in turn.

Compare the processing on the browser side:

Process.nextTick () VS setImmediate ()

In essence, the names should be swapped. Process.nextTick () fires more immediately than setImmediate ()

An interesting sentence from the official document, from a semantic point of view, setImmediate () should be executed before process.nextTick (). In fact, on the contrary, naming is a historical reason and it is hard to change.

Process.nextTick () is executed between the event phases, and once executed, it will not proceed to the next event phase until the nextTick queue is cleared, so if process.nextTick () is called recursively, it will cause the problem of readFile O starving (hunger). For example, the readFile in the following example has been completed, but its callback has not been executed:

Const fs = require ('fs') const starttime = Date.now () let endtimefs.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 ()

The running result of process.nextTick ():

NextTick 1nextTick 2.nextTick 999nextTick 1000finish reading time: 170

Replace it with setImmediate (), and run the result:

SetImmediate 1setImmediate 2finish reading time: 80.setImmediate 999setImmediate 1000

This is because the setImmediate () callback of the nested call is scheduled to be executed at the next event loop, so there is no blocking.

This is the end of the content of "what is the mechanism of the event loop in Node.js". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report