This article has participated in the third “topic writing” track of the Denver Creators Training Camp. For details, check out: Digg Project | Creators Training Camp third is ongoing, “write” to make a personal impact.

📢 Hello everyone, I am Xiao Cheng, a prospective sophomore front-end enthusiast

📢 this article will take you through the process of understanding how JavaScript works

📢 May you be true to yourself and love life

The introduction

In some interviews, we may be asked this question

How does JavaScript work?

You might be asked for code like this

setTimeout(function () {
    console.log('Timer's on.')});new Promise(function (resolve) {
    console.log('Execute for loop now');
    for (var i = 0; i < 10000; i++) {
        i == 99 && resolve();
    }
}).then(function () {
    console.log('Execute the then function')});Copy the code

These may seem abstruse and complex, but if you understand how JavaScript works, these problems can be solved

First attached is the outline of this article, this article will analyze the operation mechanism of JavaScript from these three aspects

First, let’s talk about single threads in JavaScript

1. Why single thread?

JavaScript is known to be a single-threaded language, and it has its fair share of drawbacks, so why not make it multithreaded?

In fact, this problem appears in the application scenario of JavaScript, we usually use JavaScript to manipulate DOM elements, which is not a problem now. But think about what would happen if JavaScript became a multithreaded language.

Imagine the following scenario

What happens when a piece of JS code deletes a DOM element and a piece of JS code changes a DOM element style when they are executed together?

Not to mention what the browser should do, I don’t know what to do, the browser will crash…

To avoid this, JavaScript is designed to be a single-threaded language

Single-threaded means that only one task can be executed at a time, and all other tasks need to be queued

But in order to have multithreaded function, there are a lot of attempts

The Web worker standard is proposed in HTML5, which provides a complete set of APIS to allow the execution of another thread outside the main thread. However, this does not mean that JavaScript has the ability of multi-threading from now on, and we cannot use it to manipulate DOM elements.

There is also a unique execution mechanism in JavaScript that divides tasks in the main thread into synchronous and asynchronous tasks

2. Why asynchrony?

To be able to solve problems such as code blocking caused by single threads

JS is single-threaded, we can imagine a ticket Windows, there are a lot of people line up to handle the business in the window, and only a JS a handle, that if a customer needs a lot of, to handle the business time is very long, so the team can only wait for the others, is equivalent to the code block, namely the browser feign death, waiting for code execution

Hence the concept of synchronous and asynchronous tasks

Is the need to distinguish through this, will deal with those long business time points out, until other customers after the completion of the unified processing

This is how synchronous and asynchronous tasks are explained

  • A synchronization task is a task that is queued to be executed on the main thread. A synchronization task can be executed only after the previous task is executed. For example:console.log
  • Asynchronous task: do not enter the main thread, through the event loop mechanism, register callback function in the task queue finally get the result, for example:setTimeout

Now that we know what synchronization is and what asynchrony is, let’s do a very simple problem, okay

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

The result is 1, 3, 2

The reason is that setTimeout is an asynchronous task that needs to be executed after synchronous code execution

Now let’s talk about the core of the mechanics: the event loop

3. Event loops

First let’s use a diagram to understand the event loop

It works as follows:

  1. All synchronization tasks are executed on the main thread, forming an execution stack, represented by the blue arrow in the figure above
  2. There is an asynchronous task queue outside the main thread (red arrow), which will wait until the asynchronous task returns the result and then put it on the queue
  3. When the execution stack code in the main thread is finished, that is, the synchronization task is finished, the task queue code will be read and put into the execution stack for execution
  4. Repeat the above three steps over and over again, and this is the event loop

Graphically, this is the closed loop of the three black arrows in the figure above

In other words: whenever the main thread execution stack is empty, it will read the task queue, this process is continuous, this operation mechanism is called the event loop

Now that we know about the event loop, let’s do a simple update on the previous problem

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

This time it prints 1 — 5 — 2 — 4 — 3

First of all, the timer is an asynchronous task and is put into the asynchronous task queue first. After the asynchronous task returns the result, the callback function is put into the task queue and wait for the main thread to execute it. Therefore, 2 and 4 are output before 3

4. Asynchronous task queue details

Common events that are queued for asynchronous tasks

  1. DOM events
  2. Promise
  3. An Ajax request
  4. setTimeout 和 setlnterval
  5. File upload

The time for adding an asynchronous task to the task queue is determined by the current asynchronous task. Instead of adding an asynchronous task to the task queue, the asynchronous task is put into the task queue only after the result of the current asynchronous task is returned

In the case of setTimeout, it is necessary to wait for the timer to end before adding the callback to the task queue

It can also be understood in combination with the following figure

Now that we know about task queues, we need to talk a little bit more about macro and micro tasks, which are subdivided into asynchronous tasks

5. Macro and micro tasks

There can be multiple macro task queues and only one microtask queue

So what are macro tasks and what are micro tasks?

  • Macro tasks include: HTML parsing, mouse events, keyboard events, network requests, executing mainline JS code, and timers
  • Microtasks include:promise.then, DOM rendering,async.process.nextTick

So how is it implemented?

  1. After the synchronization task in the execution stack is complete, the microtask is executed first

  2. After the microtask queue completes, the macro task is read

  3. When a microtask is encountered during the execution of a macro task, it is added to the microtask queue

  4. After the macro task is executed, the microtask queue is read again and the cycle is repeated

Let me draw a picture to help you understand it

To sum it up, a microtask is always executed before a macro task is executed

Special note: since the entry to the code is a script tag. Therefore, global tasks are macro tasks

6. The actual combat

With that in mind, let’s take a look at some classic interview questions

console.log("1");
setTimeout(function () {
    console.log("2");
    new Promise(function (resolve) {
        console.log("3");
        resolve();
    }).then(function () {
        console.log("4");
    });
});
new Promise(function (resolve) {
    console.log("5");
    resolve();
}).then(function () {
    console.log("6");
});
setTimeout(function () {
    console.log("Seven");
});
setTimeout(function () {
    console.log("8");
    new Promise(function (resolve) {
        console.log("9");
        resolve();
    }).then(function () {
        console.log("10");
    });
});
new Promise(function (resolve) {
    console.log("11");
    resolve();
}).then(function () {
    console.log("12");
});
console.log("13");
Copy the code

The answer is: 1-5-11-13-6-12-2-3-4-7-8-9-10

First cycle

  • From the global task entry, firstprintThe log1
  • Encountered macro tasksetTimeout, to the asynchronous processing module, denoted assetTimeout1
  • And then I meet the promise object,printThe log5That will bepromise.thenJoin the microtask queuep1
  • Again meetsetTimeoutTo the asynchronous processing module, denoted assetTimeout2
  • Again meetsetTimeoutTo the asynchronous processing module, denoted assetTimeout3
  • When you encounter a Promise object, print a log11That will bepromise.thenJoin the microtask queuep2
  • If a print statement is encountered, logs are directly printed13

The total number of prints in this cycle is 1 — 5 — 11 — 13

Current loop result

Second cycle

  • The microtask queue is executed firstp1 å’Œ p2First in, first out, first printed6To print12
  • After the microtask event is processed, the macro task is executedsetTimeout1
  • If a print statement is encountered, logs are directly printed2
  • The promise object is encountered again, and the log is printed3That will bepromise.thenJoin the microtask queuep3

The second cycle ends

The current operation diagram is

Third cycle

  • First, execute the microtask queue and print the log4
  • After the microtask is processed, execute the macro tasksetTimeout2
  • If a print statement is encountered, print it directly7

End of cycle

Fourth cycle

  • The microtask queue is empty, performing the macro tasksetTimeout3
  • If a print statement is encountered, the log is printed8
  • Encounter the Promise object, execute the print statement, and print9
  • willpromise.thenJoin the microtask queuep4

Fifth cycle

  • First empty the microtask queue, execute the print statement, print10
  • completed

That’s all I have to say about how JavaScript works

Thank you very much for reading, welcome to put forward your opinion, if you have any questions, please point out, thank you! 🎈