Synchronous and asynchronous tasks
// test.js setTimeout(() => console.log(1)); setImmediate(() => console.log(2)); process.nextTick(() => console.log(3)); Promise.resolve().then(() => console.log(4)); (() => console.log(5))(); // 5/3/4/1/2Copy the code
In this code (() => console.log(5))(); Is a synchronous task, so it is executed first, and the rest are asynchronous tasks.
Among them
process.nextTick(() => console.log(3));
Promise.resolve().then(() => console.log(4));
Copy the code
NextTick and promise are always executed before the next event cycle. When the timer is executed, the time threshold is calculated. When the time threshold is reached, the queue is added to the event cycle, so 3,4 are always executed before 1,2
In short, Process. nextTick and Promise are the first asynchronous tasks to execute
Second, process.nextTick is executed before promise. After Node completes all synchronization tasks, the process.nextTick task queue is executed, and promise tasks are appended to the process.nextTick task queue
So the following code always prints 3 and then 4
process.nextTick(() => console.log(3)); Promise.resolve().then(() => console.log(4)); / / 3/4Copy the code
Note that the next queue will not be executed until the previous queue has been emptied
process.nextTick(() => console.log(1)); Promise.resolve().then(() => console.log(2)); process.nextTick(() => console.log(3)); Promise.resolve().then(() => console.log(4)); // 1/3/2 // 4Copy the code
What is an Event loop
Nodejs is single-threaded. Event loops enable NodeJS to transfer non-blocking I/O operations to the kernel for execution. They can perform multiple operations in the background and notify NodeJS when one of the operations is complete. To add the callback to the polling queue for final execution
When nodeJS starts executing, it processes the input script, which may make an asynchronous API call, schedule a timer, or call process.nexttock (), and then start processing the time loop
The following diagram shows a simplified overview of the sequence of events loop operations:
Each box called the event loop mechanism, a stage, each stage has a first in first out (FIFO) callback queue, under normal circumstances, when the event loop into a given stage, it will be implemented in this phase correction in the queue, until the queue run out or to perform the maximum number of callback, when the queue run out or to implement a callback when the maximum number of, The cycle of events moves on to the next stage, and so on
Summary of stage
Timers: The callbacks of setTimeout and setInterval are executed at this stage
Pending Callbacks: ** Perform I/O callbacks deferred until the next iteration of the loop
** Idle, prepare: ** For internal use only
** Poll: ** This phase is the polling phase, used to retrieve new I/O events, wait for I/O events that have not returned a result, execute the I/ O-related callback queue, and stay in this phase if there are no other asynchronous tasks to process (such as expired timers),
Callbacks here, except for the following callbacks
· setTimeout and setInterval callbacks
· setImmediate callback
· The callback used to close the request, such as: socket.on(‘close’,…)
** This phase performs the setImmediate callback
** Close callbacks: ** This stage performs a close callback, such as: socket.on(‘close’,…)
Detailed introduction of phases
timers
The timer specifies a threshold after which a supplied callback function can be executed. Note that the threshold does not refer to the exact time of execution. The timer callback will run as soon as possible after the specified time and will be delayed if other operations are blocked
const fs = require('fs'); Function someAsyncOperation(callback) {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); someAsyncOperation(() => { const startCallback = Date.now(); While (date.now () -startCallback < 10) {// do nothing}});Copy the code
1. When the event loop reaches the polling phase (waiting in the polling phase), it has an empty queue (fs.readfile has not been completed),
2. At 95ms, the file is read and the 10ms callback is added to the polling callback queue.
3. After the callback completes, the event loop looks at the timer that has reached the threshold and returns to the timer phase to execute the timer callback
4. In this example, you’ll see that the scheduled timer and the execution timer callbacks are 105ms in total
pending callbacks
For example, if the TCP socket receives ECONNREFUSED when attempting to connect, some * NIx systems want to wait to report an error. This will be executed in the callback queue of the Pending Callbacks phase
poll
There are two main things to do at this stage
1. Calculate how long it should block and poll for I/O
2. Handle callbacks in the polling queue
When the event loop enters the POLL phase and there is no timer task, one of two things happens:
1. If the polling callback queue is not empty, the event loop will execute them synchronously in turn,
2. If the polling callback queue is empty, one of two other things will happen:
1. If setImmediate is set, the event loop ends the polling phase and continues into the Check phase, executing the callback queue
2. If setImmediate is not set, the event loop continues to wait for the callback script to be added to the queue for the current phase
In addition, whenever the polling queue is empty, the event loop checks for timers that have reached the threshold and, if one or more timers are ready, rolls back to the timer phase to execute those timer callback queues
check
Typically, when code executes, the event loop will eventually reach the polling phase, where it waits for incoming I/O events such as connections, requests, etc., but if setImmediate already arranges a callback and the route-phase callback queue is empty, it will enter the check phase rather than continue waiting for the route-phase event.
close callbacks
If a socket or handle is suddenly closed (for example: socket.destory()), a close event is emitted during this phase
SetImmediate and setTimeout
SetImmediate Because setTimeout is used in the Timers phase, setImmediate is used in the Check phase. Theoretically, setTimeout beats setImmdiate when the second parameter of setTimeout is set to 0. namely
setTimeout(() => console.log(1), 0);
setImmediate(() => console.log(2));
Copy the code
The above code is executed in order 1, 2, but the actual situation is uncertain because NodeJS cannot do 0ms. When the second parameter is greater than 2147483647 or less than 1, it is automatically set to 1, and non-integer values are automatically cut to integers
Rather, setTimeout is used to mediate events that reach 1ms, and setImmediate is used to mediate events that do not reach 1ms. The timers phase is skipped and the Timers phase is set to Check.
But if both tasks are called within the I/0 callback, setImmediate must perform before setTimeout
const fs = require('fs');
fs.readFile('test.js', () => {
setTimeout(() => console.log(1));
setImmediate(() => console.log(2));
});
Copy the code
The above code enters the Poll phase, then the Check phase, and finally the Timers phase
Reference links:
Nodejs.org/en/docs/gui…
www.ruanyifeng.com/blog/2018/0…