preface

It’s a bit clickbait, but don’t delay you from consolidating your knowledge of the cycle of events. Note is to consolidate, this article has a few easy to confuse the place, not suitable for the event loop do not understand a novice, otherwise read may be silly.

Again, 🔥🔥🔥: You may be even more confused, although this also achieved my effect

code

function test(){
  console.log(0);

  setTimeout(function() {
    console.log(1);
    
    async function async1() {
      await async2()
      console.log(2)}async function async2() {
      console.log(3)
    }
    async1()
    new Promise(function(resolve) {
      console.log(4)
      resolve()
    }).then(function(){
      console.log(5)})})new Promise(function(resolve) {
    console.log(6);
    resolve();
  }).then(function() {
    console.log(7)
  }).then(function() {
    console.log(8)
  })

  setTimeout(function() {
    new Promise(function(resolve) {
      console.log(9);
      resolve();
    }).then(function() {
      console.log(10)})})return console.log(11)
}
test()
Copy the code

The above code has 12 console. logs in total, covering a jumble of async,await, and a few of the event loops that this article is most interested in telling you about.

First, it should be obvious that this code can be broken down into five parts: a console.log(1), two setTimeout, a new Promise, and a return. As we all know, the first output must be “0” because it is on the main JS thread where test() calls the first macro task —-. The rest of the analysis comes from three aspects:

new Promise()

👀 The first one is the most basic, the middle part of the new Promise():

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

Obviously, there is no synchronized console.log code behind this Promise. As we are familiar with, both setTimeouts will wait in the macro task queue, so let’s ignore them. The 0 in front has been printed, followed by the 6 without doubt (if in doubt, please go out and turn right to find the excellent event loop article), so what’s next?

Logically, there are only two possibilities. One is to print 7, since this is the first callback into the microtask queue; The other option is to print 11, since this is the return value of the only function currently running in the JS main thread. So the question comes back to does the function return when the microtask queue is empty? Or do you recycle the microtask queue after the main process has emptied?

The answer is the latter. The main process is not idle, i.e. the microtask queue will not loop if the test function does not return. Even if you see something interesting in the browser control window:

If you don’t understand this, you can also watch the lecture on the cycle of events in this video. The author in the last five minutes of the click button and JS button execution API to the same section of code different execution sequence explained.

There is nothing left to say, after all, as the diagram above shows, when we execute the first THEN, the second THEN goes to the microtask queue, and until the microtask queue is empty, the main process goes back to the macro task queue to take down a macro task.

So the order of the first few is:

0 -> 6 -> 11 -> 7 -> 8
Copy the code

The first setTimeout

🥂 The first setTimeout has an error prone problem that is not our fault:

setTimeout(function() {
    console.log(1);
    
    async function async1() {
      await async2()
      console.log(2)}async function async2() {
      console.log(3)
    }
    async1()
    new Promise(function(resolve) {
      console.log(4)
      resolve()
    }).then(function(){
      console.log(5)})})Copy the code

First, we remove the shell of setTimeout and execute it in the following order:

1 -> 3 -> 4 -> 5 -> 2
Copy the code

That’s where the first controversy comes in, because you can copy this code to the console and print:

1 -> 3 -> 4 -> 2 -> 5
Copy the code

This result was due to an error in Node8, and later, the developers realized that the output was actually more in line with our needs, since it was more intuitive. So they started trying to plug this feature into the formal specification, and they got “–harmony-await-optimization”.

Starting with V8 V7.2 and Chrome 72, this optimization has become orthodoxy. That is, although we follow the criteria of await, on the second execution to await and await followed by a Promise, await will simply resolve and put into the microtask queue, and the statement following await statement will be executed again the next time the microtask queue loops. But we need to know that this standard ultimately succumbs to the performance optimization of await. So what we end up seeing is:

1 -> 3 -> 4 -> 2 -> 5
Copy the code

The second setTimeout

☕ above section of the first setTimeout analysis, know that we are independent of this function to explain, then combined with the second setTimeout what will be the output order? 🤷 came ️

In fact, this problem can also be transformed into a small problem to solve, we are now entangled with the two setTimeout is one after the execution of the other? Or do they alternate in order of microtask queues?

In fact, I mentioned this answer in the first part. When the microtask queue is empty, the main thread will take the first setTimeout from the macro task queue, and no doubt the setTimeout execution will push a new promise.resolve to the microtask queue. We also know that microtasks will not be executed if the JS main process does not clear them. In other words, as long as the main process has stuff and the microtask queue has stuff, the microtask queue stuff will keep executing until it’s empty.

This part is also explained in detail in the video just posted. I recommend you check out this video, although some people will get it from what I’m saying.

At this point, the answer to this question also comes out 🌺:

0 -> 6 -> 11 -> 7 -> 8 -> 1 -> 3 -> 4 -> 2 -> 5 -> 9 -> 10
Copy the code

If you understand the error welcome to point out, thank 😁