preface

My first exposure to the EventLoop the word, or in the preparation of internship interview two years ago, at that time, the first company to apply for, the interviewer wrote a bunch of setTimeout, Promise, the console. The log code to ask me execution order, I restore is meng, After that interview, I went online and saw a lot of interview questions for EventLoop, and I memorized them like I was memorizing formulas. SetTimeout was executed last,Promise and console.log were executed first, But you actually don’t even know how to the EventLoop, so lead to some problem when I dig a little bit about the interview don’t know, or their work in really encountered this kind of problem is also a hindrance, learning also want to know the why, in this two years later to detailed discuss EventLoop is what kind of a thing.

This article will not throw out the concept and title of EventLoop! This is very boring, the article is not long slowly read down.

Single-threaded JS

College everyone learned basic Java, Java as a multithreaded language, a process which can create a number of different threads to perform different tasks, everyone know the basic benefits of multiple threads when a thread is waiting for other threads will not follow waiting, is equivalent to the highway with multiple lanes, will not be because of a car broken down, All the cars can’t move, which also improves CPU utilization.

That sounds great, but why is our JavaScript single-threaded and why isn’t it multi-threaded? Aren’t we afraid that our JavaScript code will block when it executes?

Answering this question goes back to our classic DOM question. If JS is multi-threaded, which thread needs to operate on a DOM node and another thread needs to delete the DOM node, which thread should perform the task? To keep things simple, JavaScript is single-threaded from the start.

Of course, one of the new HTML5 features is web Worker, which allows JavaScript to create more threads, but these threads are strictly controlled by the main thread and cannot manipulate DOM elements.

Solve the single thread problem

Since JavaScript is single-threaded, it’s tempting to wonder if that could easily block. Wouldn’t processing time-consuming tasks, such as Ajax requests and file reads and writes, cause your program to block for a long time? So how does JS deal with that?

/ / pseudo code

console.log(a)
console.log(b)
ajax()
console.log(c)
Copy the code

If all of the above code was executed synchronously, you would have to wait for Ajax () to finish before printing the C variable, but the C variable has nothing to do with Ajax () at all, and it would be a waste of resources to let Ajax () occupy our main thread. JavaScript designers are aware of this problem, so you can suspend the task and let subsequent tasks continue with this time-consuming operation. JavaScript is divided into synchronous and asynchronous tasks for this purpose.

Synchronization tasks: Synchronization tasks are well understood, that is, the main thread is executed in code order, the previous task is executed before the next task is executed.

Asynchronous task: The asynchronous task is not executed in the main thread. After the asynchronous task is executed, a callback function is put into the task queue. After the main thread is executed, the main thread reads the task queue and starts to execute the task.

The task execution flow chart in the main thread can be summarized as follows:

Now that we know the order in which synchronous and asynchronous tasks are executed, let’s run the following program:

console.log(1)
setTimeout(() = >{
    console.log(2)},0)
setTimeout(() = >{
    console.log(3)},0)
console.log(4)
Copy the code

Perform synchronous task 1->4 first, and add the asynchronous task to the task queue (first in, first out) to obtain 2->3. The combination of the two can obtain 1->4->2->3

Now, of course, the fundamental questions can not be so simple, such as the following:

console.log(1)
setTimeout(() = >{
    console.log(2)},0)
new Promise((resolve) = >{
    console.log(3)
    resolve()
}).then(() = > {
    console.log(4)})console.log(5)
Copy the code

If the answer is 1->5->3->2->4, but the answer is clearly wrong, so we need to clarify the definition of asynchronous task is macro task and micro task.

EventLoop

What are macro tasks and what are micro tasks?

Macro tasks: Macro tasks include Script, setTimeout, setInterval, setImmediate, I/O, AND UI rendering.

Microtasks: Microtasks include process.nextTick (available in Node), Promise, and MutationObserver.

So asynchronous tasks are divided into macro tasks and micro tasks. What is the order of their execution?

1) After the synchronization task in the main thread is completed, the main thread will check whether there are any executable tasks in the microtask queue of the asynchronous task. Similarly, the task is executed first (the execution order of the queue).

2) After the execution of tasks in the microtask queue, the main thread will check whether there are executable tasks in the macro task queue, and the task execution sequence is also the first to be executed.

3) After the execution of micro task and macro task, the asynchronous task is completed. The above asynchronous task is executed in a continuous loop ♻️, which is often referred to as an EventLoop.

So let’s look at the question we got wrong:

console.log(1)
setTimeout(() = >{
    console.log(2)},0)
new Promise((resolve) = >{
    console.log(3)
    resolve()
}).then(() = > {
    console.log(4)})console.log(5)
Copy the code

1->3->5->4->2

EventLoop exercises

/ / exercise 1

console.log(1)

setTimeout(function() {
  console.log(2)},0)

new Promise(resolve= > {
  console.log(3)
  resolve()
})
.then(function() {
  console.log(4)
})
.then(function() {
  console.log(5)})console.log(6)

Copy the code

If the synchronization task has 1,3, and 6, the synchronization task can be executed one by one to obtain 1->3->6, while the microtask has 4->5, which is put into the microtask queue 4->5, and the macro task only has 2, which is put into the macro task queue. Finally, we can get the answer as 1->3->6->4->5->2 in the order of synchronous task > micro task > macro task.

2 / / practice

console.log(1);
setTimeout(function() {
    console.log(2);
    new Promise(function(resolve) {
        console.log(3);
        resolve();
    }).then(function() {
        console.log(4)})setTimeout(function(){
        console.log(5)})})new Promise(function(resolve) {
    console.log(6);
    resolve();
}).then(function() {
    console.log(7)})Copy the code

1->6->7->2->3->4->5

/ / 3

console.log(1)

async function async1() {
    await async2()
    console.log(2)}async function async2() {
    console.log(3)
}

async1()

setTimeout(function() {
  new Promise(function(resolve) {
    console.log(4);
    resolve();
}).then(function() {
    console.log(5)})},0)

new Promise(function(resolve) {
    console.log(6);
    resolve();
}).then(function() {
    console.log(7)
}).then(function() {
    console.log(8)})Copy the code

1->3->6->2->7->8->4->5

new Promise((resolve, reject) = > {
    console.log(3)
    resolve()
}).then(() = > {
    console.log(2)})Copy the code

In this case, 2 will be added to the microtask queue, and 2 will be executed first because it enters the microtask queue before 4,5,7, and 8, while 4,5 are microtasks executed in macro tasks, and will be added to the microtask queue at last. Therefore, the order of microtasks is 2->7->8->4->5, and the order of synchronization tasks is 1->3->6. 1-> 6->2->7->8->4->5.

conclusion

In fact, once you understand how JS and EventLoop work, the problem of solving EventLoop is basically the same.

Reference:

More on the Event Loop

Yck: Front-end interviewing