In-depth understanding of the event loop (event loop) mechanism in Javascript

interview questions

During our interview, some interviewers may ask us: "Can you introduce the JavaScript event loop mechanism?" or "Do you know about micro-tasks and macro-tasks?"

Or people don't bother to ask us, just throw the following interview question to us, let us write its final execution result;

console.log('1')

setTimeout(function callback(){
    
    
	console.log('2')
}, 1000)

new Promise((resolve, reject) => {
    
    
    console.log('3')
    resolve()
})
.then(res => {
    
    
    console.log('4');
})

console.log('5')

The output is: 1, 3, 5, 4, 2

It’s the same as what you think No, if you do it right, then you don’t need to look down, it’s a waste of time; if it’s wrong, then let’s study why it’s the above print result together;

The above three behaviors are actually to examine our understanding of the event loop (event loop) mechanism;

Then today we will explore around this interview question. After reading it, you will only sigh with emotion: That’s it, it’s so fucking simple!

JavaScript is single threaded

JavaScript is a single-threaded programming language , which means that only one thing can be done at the same time, and all tasks need to be queued to complete in sequence;

So, why can't JavaScript have multiple threads?

Answer : As a browser scripting language, the main purpose of JavaScript is to interact with users and manipulate the DOM. This determines that it can only be single-threaded, otherwise it will bring very complicated synchronization problems. For example, assuming JavaScript has two threads at the same time, one thread adds content to a certain DOM node, and the other thread deletes the node, which thread the browser should take as the standard;

Therefore, in order to avoid complexity, JavaScript has been single-threaded since its inception, which has become the core feature of this language and will not change in the future.

Synchronous tasks and asynchronous tasks

Single thread means that all tasks need to be queued, and the next task will be executed only after the previous task is completed. If the previous task takes a long time, the latter task will have to wait forever.

Let's take some of the code above, as follows:

console.log('1')

setTimeout(function (){
    
    
	console.log('2')
}, 1000)

console.log('3')

/* 运行结果:
	1
	3
	2
*/

At this time, some people wonder, isn’t Js single-threaded, it should be executed line by line from top to bottom, and the next line of code will be executed only after the previous line of code is executed, then it should print out: 1, 2, 3 ; Then why is it: 1, 3, 2;

JavaScript developers realize that in order not to affect the normal operation of the main thread, they hang up those time-consuming tasks (such as timers, Ajax operations to read data from the network, etc.) After the task of the thread is executed, go back and continue to execute the tasks in the queue;

Therefore, tasks can be divided into two types:

  • Synchronous tasks : tasks that are queued for execution on the main thread, the next task can only be executed after the previous task is completed;
  • Asynchronous task : A task that does not enter the main thread but enters the "task queue". Only when the "task queue" notifies the main thread that an asynchronous task can be executed will the task enter the main thread for execution.

event loop (event loop)

In fact, the above code execution animation is roughly as follows: (The picture comes from "Zero One")
insert image description here

The execution mechanism process is as follows:

  • All synchronization tasks are executed on the main thread, forming an execution stack (call stack);
  • In addition to the main thread, there is also a 'task queue' (task queue). Various Web APIs in the browser provide a separate running space for asynchronous code. The callback is sent to the task queue (the queue follows the first-in-first-out principle)
  • Once all the synchronous tasks in the stack of the main thread are executed, when the call stack is empty, the system will push the callback functions in the queue into the call stack for execution. When the call stack is empty, the system will continue to loop through the task queue Is there any code that needs to be executed in

In fact, this process is the event loop mechanism we need to understand ;

Now you know why the printed result is: 1, 3, 2;

Macrotasks and Microtasks

Let's go back and look at this interview question:

console.log('1')

setTimeout(function callback(){
    
    
	console.log('2')
}, 1000)

new Promise((resolve, reject) => {
    
    
    console.log('3')
    resolve()
})
.then(res => {
    
    
    console.log('4');
})

console.log('5')

Extension : This involves the Promise constructor, so I won’t talk about it here; everyone knows that the Promise function is executed synchronously, and the .then method can be executed asynchronously;

I mentioned synchronous and asynchronous tasks above, and I also learned about the event loop (event loop) mechanism. Everyone knows that the asynchronous task must be executed after the synchronous task of the call stack is executed, so first print out: 1, 3, 5, This is no problem, setTimeout() and Promise() are both asynchronous tasks, then setTimeout() is inserted into the asynchronous task queue before Promise(), why is 4 printed first, not 2?

In fact, asynchronous tasks are also different, divided into: macrotask (macrotask) and microtask (microtask)

Commonly used macro tasks and micro tasks in browsers:

name event
macro task setTimeout 、setInterval 、UI rendering
micro task promise 、requestAnimationFrame

So since asynchronous tasks are divided into macro tasks and micro tasks, the queue must also be divided into macro task queues and micro task queues;

When both the macrotask and the microtask are in the task queue (Task Queue), the priority of the microtask is higher than that of the macrotask, that is, the microtask is executed first, and then the macrotask is executed;

In fact, the above code execution animation is roughly as follows: (The picture comes from "Zero One")
insert image description here

The execution mechanism process is as follows:

  1. Step 1: While the main thread is executing synchronous tasks, put some asynchronous tasks into the 'task queue' (task queue), wait for the call stack of the main thread to be empty, and then go out of the queue to execute tasks in turn;
  2. Step 2: Check whether the micro-queue in the task queue is empty, if it is not empty, take out a micro-task and push it into the stack for execution; then continue to step 2; if the micro-queue is empty, start to take out one of the macro-queues Macro task execution;
  3. Step 3: After executing a macro task in the macro queue, it will continue to check whether the micro queue is empty. If there is a newly inserted task, continue to the second step; if the micro queue is empty, continue to execute the macro task in the macro queue. The next task, and then continue to execute the third step in a loop;

The above execution steps can be seen in conjunction with the animation, must be understood, must be understood!

Now I know why it prints out: 1, 3, 5, 4, 2;

detection practice

In order to see if you really understand, you can look at the following code, the printout is?

setTimeout( () => {
    
    
  console.log('1')
  Promise.resole().then( () => {
    
    
    console.log('2')
  })
},0)

new Promise((resolve, reject) => {
    
    
    console.log('3')
    resolve()
})
.then(res => {
    
    
    console.log('4');
})

console.log('5')

Guess you like

Origin blog.csdn.net/qq_44182284/article/details/121158680