As we all know, javascript is a single-threaded language, so in order to achieve the main thread does not block, Event Loop scheme came into being.
Event Loops in browsers are not the same as Event loops in Node, which are a specification defined in HTML5 and implemented by the Libuv library in Node.
Event loop in browser
-
All synchronization tasks are executed on the main thread, forming an execution stack
-
In addition to the main thread, there is a task queue.
-
Task queues are divided into macro-tasks and micro-tasks.
-
Macro-task: setTimeout, setInterval, setImmediate, I/O, etc
-
Micro-task: Process. nextTick, native Promise(some implemented promises put then methods in macro tasks),Object.observe(deprecated), MutationObserver, etc
-
The entire basic Event Loop looks like this:
Specific process:
-
In the browser, the current stack is executed first, and the tasks in the main thread are completed.
-
Remove the Microtask from the Microtask queue until it is empty.
-
Pull out a task from the Macrotask to execute.
-
Check whether microtasks exist in microtasks and execute them until they are cleared.
-
Repeat 3 and 4.
This whole mechanism is called an Event Loop
example
Now that you know the browser’s Event loop, look at the following example and guess what the browser’s output is
console.log(1);
console.log(2);
setTimeout(function(){
console.log('setTimeout1');
Promise.resolve().then(function(){
console.log('Promise')})})setTimeout(function(){
console.log('setTimeout2'); }) // Browser output: 1 2setTimeout1 Promise setTimeout2Copy the code
Event loop in node
-
There is such an event loop mechanism inside Libuv. The event loop is initialized when node starts.
-
The Event loop in Node is divided into six stages. Different from the browser, each stage corresponds to an event Queue. The Node will complete all tasks in the current stage, clear the NextTick Queue and Microtask Queue, and then execute the next stage.
-
In Node.js, the Process object represents the Node.js application and can obtain information about the application’s user, running environment, and so on. The process.nexttick () method adds callback to the Next Tick queue, and nextTick has a higher priority than microtasks such as Promises.
Timers: Execute the callback that expires in setTimeout() and setInterval().
I/O Callbacks: A small number of I/ OCallbacks in the previous cycle are delayed until this stage of the cycle
Idle, prepare: Moves the queue. It is used internally only
Poll: The most important phase, performing I/O callback, will block in this phase under appropriate conditions
Check: Performs the Callback of setImmediate
Close callbacks: Callback to execute a close event, such as socket.on(“close”,func)
example
See the following example to further understand the Event loop
Execute the following code in Node and find that the order of execution is different each time. Because node requires startup time, setTimeout may or may not run out of time during execution, so the order of execution depends on node execution time.
setTimeout(function(){
console.log('timeout')})setImmediate(function(){
console.log('immediate')})Copy the code
After the I/O phase is complete, the Check phase is used, so setImmediate takes precedence
let fs=require('fs');
fs.readFile('./1.log'.function(){
console.log('fs');
setTimeout(function(){
console.log('timeout')})setImmediate(funciton(){
console.log('setTimmediate')})})Copy the code
NextTick application scenarios
function Fn(){ this.arrs; Process.nexttick (()=>{// Depending on the nature of nextTick, we can assign the value first and then use this.arrs() in the next queue; }) } Fn.prototype.then=function(){
this.arrs=function(){console.log(1)}
}
letfn=new Fn(); fn.then(); // Note: nextTick must not be written recursively, otherwise it will cause an infinite loop. You can put some ratiosetTimeout Indicates the priority task to executeCopy the code
conclusion
-
MicroTask microtasks run before MacroTask in the same context.
-
The browser takes out a MacroTask and executes it, and then executes all the tasks in the MicroTask. Node executes in six phases, with each phase switching before executing the MicroTask queue
-
Process.tick () is better than Promise on the same MicroTask queue
-
SetImmdieate () and setTimeout(), if they are called outside of the asynchronous I/O callback (called inside the I/O because the next phase is the check phase), the order of execution is uncertain, depending on how long the loop takes before execution.