1. An overview of the
-
Just like in browsers, there are Event loops in NodeJS
-
However, the host environment and application scenarios of executing the code are different
-
So the event cycles are different
2. Difference between NodeJS event ring and browser event ring
2.1 Different Number of Task Queues
-
The browser event ring has two event queues (macro and micro task queues)
-
The NodeJS event ring has six event queues
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ > │ timers │ execution setTimeout and setInterval () () callback due │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ pending callbacks │ execution system callback operation, such as TCP, Udp communication error callback │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ idle, Prepare │ only used in internal │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ poll │ execute callback │ associated with I/O (Almost all callbacks are executed except for close callbacks, timer callbacks, and setImmediate()); │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ check │ perform setImmediate callback │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ┤ close callbacks │ perform the close event callback, for example socket. On (" close ", func) └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘Copy the code
2.2 Different microtask queues
-
The browser event ring has a queue dedicated to storing microtasks
-
There is no queue dedicated to microtasks in the NodeJS event ring
2.3 Different execution timing of microtask (abolition)
-
The browser event loop empties the microtask queue after each macro task is executed
-
NodeJS event loop only goes back to empty the microtask queue when switching between other queues after the synchronization code has finished executing (previous version)
now
The event ring of Node is basically the same as the event ring of the browser. The synchronization code is executed first, and the microtask queue will be emptied after completion of the synchronization code. After completion of the synchronization, the microtask queue will be emptied according to the priority of the event ring queue
2.4 Different priorities of microtasks
-
If multiple microtasks in the browser event ring meet the execution conditions at the same time, fifO is adopted
-
If multiple microtasks in the NodeJS event ring meet the execution conditions at the same time, they will be executed according to the priority
Common macro tasks include Promise, MutationObserver, and process.nexttick
However, MutationObserver is not a Node macro task, because it listens for changes in the DOM tree. Do you have a DOM tree? The only common macro tasks in Node are Promise, process.nexttick
Which of these two has higher priority?
Let’s write a code to see what’s going on
Promise.resolve().then(function () {
console.log("Promise");
});
process.nextTick(function () {
console.log("process.nextTick1");
});
process.nextTick(function () {
console.log("process.nextTick2");
});
process.nextTick(function () {
console.log("process.nextTick3");
});
Copy the code
Let’s see what happens
According to the figure, the priority of Process. nextTick is higher than that of promise
After the process.nextTick code is executed, the Promise code will be executed
3. Complete process
Take a look at two examples to get a basic idea of the complete flow of Node code execution
The first example
setTimeout(function () { console.log("setTimeout"); }); Promise.resolve().then(function () { console.log("Promise"); }); Console. log(" sync code Start"); process.nextTick(function () { console.log("process.nextTick"); }); setImmediate(function () { console.log("setImmediate"); }); Console. log(" sync code End");Copy the code
So let me just give you a quick overview
Execute code from top to bottom, first encounter a setTimeout, this is not asynchronous code,setTimeout belongs to the Timers queue, put this setTimeout into the Timers queue
Then we come across a Promise, and if it’s also asynchronous code, and if a Promise is a microtask, we’ll assume for the moment that a queue holds Node’s (microtask), and we’ll put the Promise on the hypothetical queue
Then it encounters a console.log, and if this is a synchronization code, and if the synchronization code is executed immediately, it prints the synchronization code Start
NextTick is also an asynchronous code,process.nextTick is a microtask, and put process.nextTick into a hypothetical queue
And then when you see setImmediate, which is not an asynchronous code,setImmediate belongs to the check queue, you put setImmediate in the check queue
Finally, a console.log is encountered, and if this is a synchronization code, the synchronization code is not executed immediately, the output synchronization code End
After the synchronization code is executed, the microtasks that meet the conditions will be executed immediately
Is the synchronization code done, and then the microtask, which has a promise and nextTick, is done on a first-in, first-out basis in the browser, whereas Node is done on a priority basis
NextTick has a higher priority than PROMsie, so the nextTick code will be executed first
The promise code is then executed, followed by the promise output
After the execution of microtasks is completed, are they executed in accordance with the queue order of Node event rings? SetTimeout belongs to the Timers queue. SetImmediate Indicates that the state of the check queue is similar to the state of the timer queue
It is said that after a Node queue in a ring of events later, she will go to see if there are any more satisfy the conditions of micro task code, if executed immediately, don’t meet don’t perform, after execution timers queue, micro task is no task, and then will jump to check queue, and then execute the check queue, print out in the end setImmediate
How do I verify my claim
Let’s take a look at the results
Is there no problem
Let’s look at the second example
Second example
setTimeout(() => {
console.log('s1');
Promise.resolve().then(() => {
console.log('p1');
})
process.nextTick(() => {
console.log('n1');
})
})
console.log('start');
setTimeout(() => {
console.log('s2');
Promise.resolve().then(() => {
console.log('p2');
})
process.nextTick(() => {
console.log('n2');
})
})
console.log('end');
Copy the code
Let me just make it very simple
Work from top to bottom
When a setTimeout is encountered, the asynchronous code is not executed immediately. SetTimeout belongs to the Timers queue and is put into the timers queue
If console.log is encountered, it belongs to the synchronization code, execute immediately, print start
Another setTimeout is encountered. The asynchronous code is not executed immediately. SetTimeout belongs to the timers queue and is put into the timers queue
When the synchronization code is finished, go back to the microtask. Now there is no task in the microtask, it will be executed according to the priority of the event ring Based on the principle of first-in, first-out (FIFO),s1 is executed as soon as it comes first. If console.log is encountered, it belongs to synchronous code and is executed immediately. Print S1; if a promise is encountered, it belongs to asynchronous code and is not executed immediately It’s a microtask, pretend it’s a microtask queue and you put a promise in it, and then when you get a nextTick, it’s asynchronous code and you don’t execute immediately,nextTick is a microtask queue that you put in an imaginary task, and s1 is done
After the execution of S1, does it say that the microtask will be executed after the execution of a queue? Check whether the code in the microtask satisfies promise and nextTick? According to the principle of priority,nextTick will be executed first, so print N1, then promise, and print P 1
After the microtask is executed, run the timers queue. After s1 is executed, s2 is left. When console.log is encountered, the synchronous code should be executed immediately and s2 is printed The promise is put in, and when it gets a nextTick, it’s asynchronous code that doesn’t execute immediately, and the nextTick is a microtask that’s put in an imaginary task queue, and S2 is done
After the execution of S2 is complete, does it say that the microtask will be executed after the execution of a queue? Check whether the code in the microtask satisfies promise and nextTick? According to the principle of priority,nextTick will be executed first, so print N2, then execute promise, then print P 2
How do you verify my claim?
Let’s look at the output
Is there no problem
Isn’t that easy
4. Interview questions
Pay attention to the point
When the following code is executed, the result is random
setTimeout(() => {
console.log("setTimeout");
});
setImmediate(() => {
console.log("setImmediate");
});
Copy the code
Take a look at the printout
Why is that?
Because the delay time specified in NodeJS is variable, the output is random
If we do not set the delay time here, does it mean that the delay time is 0s? Because there is some error in the delay time, is it possible that the delay time is 0.1 or 0.2? Is it possible that the following code will be executed immediately after the delay
This is not an interview question, of course, just to get a feel for it
These are the interview questions
The interview questions
SetImmediate Mediate Does not mediate setTimeout Does not mediate
const path = require("path");
const fs = require("fs");
fs.readFile(path.join(__dirname, "04.js"), () => {
setTimeout(() => {
console.log("setTimeout");
});
setImmediate(() => {
console.log("setImmediate");
});
});
Copy the code
Take a look at the printout
Then why on earth?
Let me just do a quick analysis
As usual, we execute code from top to bottom, and we encounter a readfile, which is asynchronous code that doesn’t execute immediately, and the readfile belongs to the poll queue
If there is no such microtask, it will be executed according to the priority of the queue. Currently, there is only one poll queue. This readfile can be executed if it meets the requirement SetTimeout indicates that timers do not perform. Instead, setImmediate mediate mediate mediate mediate mediate mediate mediate mediate mediate mediate mediate mediate mediate Mediate Mediate Mediate Mediate Mediate Mediate Mediate Mediate Mediate If there are no microtasks at the moment, then the check queue will be switched. Why? Rather, setImmediate does not allow the operator to run through the poll queue. Rather, setImmediate does not allow the operator to run through the poll queue