preface

I haven’t written my blog for a long time, because I am busy with my studies and typing………. Dove for a long time sorry sorry Orz

If you are more capable, I fully recommend you go directly to the official documentation nodejs.org/zh-cn/docs/…

Here is on the basis of official documents to do their own analysis and understanding.

The body of the

Event loop operation sequence:

┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ > │ timers │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ pending Callbacks │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ idle, Prepare │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ incoming: │ │ │ poll │ < ─ ─ ─ ─ ─ ┤ connections, │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ data, Etc. │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ check │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ┤ close callbacks │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘Copy the code

This paper focuses on the three stages of timers, poll and check

Part 1. Timers

From official:

The timer specifies the threshold at which the provided callback can be executed, not the exact time the user expects it to be executed. After a specified interval, timer callbacks are run as early as possible. However, operating system scheduling or other running callbacks can delay them.

Pay attention to:pollingphaseControls when the timer is executed.

For example, suppose you schedule a timer that expires after 100 milliseconds, and then your script starts asynchronously reading a file that will take 95 milliseconds:

const fs = require('fs');

function someAsyncOperation(callback) {
// Assume this takes 95ms to complete
 fs.readFile('/path/to/file', callback);
}

const timeoutScheduled = Date.now();

setTimeout(() = > {
 const delay = Date.now() - timeoutScheduled;

 console.log(`${delay}ms have passed since I was scheduled`);
}, 100);

// do someAsyncOperation which takes 95 ms to complete
someAsyncOperation(() = > {
const startCallback = Date.now();

 // do something that will take 10ms...
 while (Date.now() - startCallback < 10) {
   // do nothing}});Copy the code

When the event loop enters the polling phase, it has an empty queue (fs.readfile () is not yet complete at this point), so it will wait for the remaining milliseconds until the fastest one of the timer thresholds is reached. When it waits 95 milliseconds for fs.readfile () to finish reading the file, its callback, which takes 10 milliseconds to complete, is added to the polling queue and executes the > line. When the callback is complete, there are no more callbacks in the queue, so the event loop mechanism looks at the timer that reached the threshold the fastest and then goes back to the timer phase to execute the timer callback. In this example, you will see that the total delay between scheduling the timer and its callback being executed will be 105 milliseconds. Note: To prevent the polling phase from starving the event loop, Libuv (the C library that implements node.js event loops and all of the platform’s asynchronous behavior) also has a hard maximum (system dependent) before stopping the polling to get more events.

Notice this sentence:

When the event loop enters the polling phase, it has an empty queue (fs.readfile () is not yet complete at this point), so it will wait for the remaining milliseconds until the fastest one of the timer thresholds is reached.

Means there is a blocking process in the polling phase (synchronous wait means blocking)

This blocking is not static and emptens the queue when the polling queue is called by an empty – > callback (in this case fs.readfile ()), executing a callback that may delay the upcoming timer function

General process ->

[                               ] 0ms

-> Calculate the blocking time

-> Wait for [fs.readFileCallback] 95ms This is an unexpected event (may not happen)

->readFileCallback to end 105ms

-> the time callback has been detected, albeit 5ms late

-> Return to the Timer phase

-> Execute the time callback

The Pending callback phase is skipped because it does not affect the understanding of the event queue

Part 2. Polling Stage

The polling phase has two important functions:

  1. Calculate the time when I/O should be blocked and polled. [1]

  2. Then, the events in the polling queue are processed.

When the event loop enters the polling phase and there is no scheduled timer, one of two things happens:

If the polling queue is not empty, the event loop loops through the callback queue and synchronously executes them until the queue is exhausted or a system-specific hard limit is reached. [2]

If the polling queue is empty, two more things happen:

If the script is dispatched by setImmediate(), the event loop ends the polling phase and continues the checking phase to execute those dispatched scripts.

If the script is not dispatched by setImmediate(), the event loop waits for the callback to be added to the queue and then executes immediately.

Once the polling queue is empty, the event loop checks for timers that have reached the time threshold. If one or more timers are ready, the event loop loops back to the timer phase to execute the callbacks for those timers.

Check phase This phase allows a callback to be performed immediately after the polling phase is complete. If the polling phase becomes idle and the script is queued after using setImmediate(), the event loop may continue to the check phase instead of waiting.

SetImmediate () is actually a special timer that runs during a separate phase of the event loop. It uses a Libuv API to schedule callbacks to be executed after the polling phase is complete.

Typically, when executing code, the event loop eventually hits the polling phase, where it waits for incoming connections, requests, and so on. However, if the callback has already been scheduled using setImmediate() and the polling phase becomes idle, it will end the phase and continue to the check phase rather than continue waiting for the polling event.

Note [1] The guess is related to the hard maximum value of the timer phase. In this case, it is necessary to calculate the total time of the polling phase.

Note [2] The polling queue refers to an event queue, but other than official articles, many articles describing the event loop like to call it an event queue. Is this a long-standing misunderstanding?

Personal description of this stage:

[1] Calculate polling time T1

[2] Handle polling queue events

[3] Judge the polling queue

Not empty -> Execute events in the queue within T1 whenever possible

Empty -> Wait for the callback to be added and then execute immediately

Empty -> (Special Case) During this period, if mediated by setImmediate, it goes straight to the next stage.

Part 3. Check

This phase allows staff **[1]** to perform a callback immediately after the polling phase is complete. If the polling phase becomes idle and the script is queued after using setImmediate(), the event loop may continue to the check phase instead of waiting.

SetImmediate () is actually a special timer that runs during a separate phase of the event loop. It uses a Libuv API to schedule callbacks to be executed after the polling phase is complete.

Typically, when executing code, the event loop eventually hits the polling phase, where it waits for incoming connections, requests, and so on. However, if the callback has already been scheduled using setImmediate() and the polling phase becomes idle, it will end the phase and continue to the check phase rather than continue waiting for the polling event. [2]

[1] people? To be honest, I don’t really know what people mean by programmers? But looking at the English document, the personnel here is people. Some doubts

[2] The mediate mediate mediate mediate mediate mediate mediate mediate Mediate Mediate Mediate Mediate Mediate Mediate Mediate Mediate Mediate Mediate The check phase is for setImmediate. What does setImmediate do?

Part 4. Close callbacks

If a socket or handler is suddenly closed (such as socket.destroy()), the ‘close’ event is emitted at this stage. Otherwise it will be issued through process.nexttick ().

When this phase is over, Node returns to timers for a cycle of events,