preface

The reason for writing this article is that I saw you in the group and then discussed the content of this part. I don’t know much about this part, so I wrote this article on the spur of the moment. Many beginners also know a little about this part, but find it troublesome and complicated in the middle of learning, so I gave up. Originally planned to take an examination of the operating system to write over, the results encountered CPU class set… So the article was written on and off for many days


Event Loop

In a nutshell, event loop is a specification of the execution order of JS code (task scheduling algorithm).

Let’s look at two pictures

JS engine

via: sessionstack

JS runtime

via: sessionstack

NOTE:

A Web worker or a cross-domain iframe has its own stack, heap, and message queue. Two different runtimes can communicate only through the postMessage method. This method adds messages to another runtime if it listens for message events.

HTML Eventloop

via: livebook.manning.com/#! / book/SEC…

This illustration is a visualization of the Event loop in the HTML specification developed by the WHATWG

When we write web code, we usually work with the JS Runtime

Synchronization code

No doubt in order

console.log(2); // Non-asynchronous code
console.log(3); // Non-asynchronous code
Copy the code

It’s obviously going to be 2, 3

Non-blocking code

There are generally two types of tasks, macroTasks and microTasks

The Event loop contains queues that maintain two different asynchronous task queues, macroTasks(Tasks) and microTasks

  • Macro tasks include: setTimeout, setInterval, setImmediate, I/O, UI Rendering

  • Microtasks include: native Promises (some implemented promises put then methods into macro tasks), Object.Observe (deprecated), MutationObserver, and MessageChannel

Each time you start executing a piece of code (a script tag) is a macroTask

1, the event loop start

2. Extract a task from the macroTasks queue and execute it

3. MicroTasks clear the queue for execution. If a task cannot be executed, push it to the next microTasks

4. End event-loop

It is worth mentioning that in the HTML standard there is a compound microtask that may execute a subTask when executed. Executing compound Microtasks can be quite complicated. I didn’t find a specific implementation process for this part at WHATWG either

const p = Promise.resolve();
p.then((a)= > {
  Promise.resolve().then((a)= > {
    console.log('subTask');
  });
}).then((a)= > {
  console.log('compound microTasks');
});
// subTask
// compound microTasks
Copy the code

The two THEN of P should be executed first, and the next eventLoop should be executed when the microTask is discovered during the then callback, but the result is the opposite

The actual process of executing code in the browser is the whole process below, and the process of writing code awareness is in the red box (so if someone asks you macroTask or microTask in the future, don’t say microTask).

setTimeout((a)= > {
  console.log(123);
});

const p = Promise.resolve(
  new Promise(resolve= > {
    setTimeout((a)= > {
      resolve('p');
      console.log(55);
    }, 1000);
    new Promise(resolve= > {
      resolve('p1');
    }).then(r= > console.log(r)); })); setTimeout((a)= > {
  console.log(456);
});

p.then(r= > console.log(r));
Copy the code

You can try to guess the order in which this code is executed, and I think a lot of people would be confused if it weren’t for this introduction, but with this introduction and our step by step analysis, you’ll get the idea

  • In the first step, the code executes until the first setTimeout prints the function 123 and pushes it into the macro task queue
  • In the second part, the code executes to the promse. resolve new Promise and does nothing… Proceed with the following code
  • Third, the code executes to the setTimeout in new Promise, and the function that prints 55 is pushed into the macro task queue
  • In the fourth step, the code executes to the New Promise inside the New Promise, executes the constructor, and pushes the THEN function to the microtask queue
  • In step 5, the code executes to the first setTimeout to print the function 456 and push it into the macro task queue
  • In step 6, the code is executed to the last P. Teng and pushed into the microtask queue

The number or variable after the function name is what the function prints to distinguish the function

After scanning these codes, the situation of each task queue is shown as follows (note that setTimeout provided by the browser at this time will check whether each scheduled task is out of time, if so, it will push into the task queue, so the timing 1000ms callback function does not appear in macroTask at this time) and then execute the synchronization code. Start executing Macro Task and Micro Task as described above

Execute micro Task first, take out P.teng P1 and print P1 if it is executable. Then take out P. Teng p and find it is not executable, that is, the status is “pending”, the macro Task is executed after the micro Task is executed, take out setTimeout 123 and find it is executable (the synchronization code has been executed at this time), If the macro Task has been executed for some time, the macro Task has been executed. If the macro Task has been executed for some time, the macro Task has been executed

So the printed result of this piece of code is

5
p1
123
456
55
p
Copy the code

Did you get it right? This is just a small case, not async yet, so let’s see async

async/await

When an async function executes an await inside it, it signals that the async function is about to give up the thread (I personally feel that this is like executing a special function that pushes the end of the first microtask queue), When the function or expression following the await statement in an async function is finished, the function immediately exits execution, the call stack is destroyed, and the rest of the code is returned to execution at the end of this event loop

Let’s see what MDN says

An async function can contain an await expression that pauses the execution of the async function and waits for the passed Promise’s resolution, and then resumes the async function’s execution and returns the resolved value.

An async function can contain an await expression that suspends the async function and waits for the returned Promise resovle/reject to complete, then resumes the async function and returns the parsed value

Should you know why await expressions cause async functions to give up threads? (If the thread is not released, it is better to write synchronous code and block all the following code), combined with the previous Event Loop, we can confirm that await expression needs to wait for Promise parsing to complete, await to resume async function execution needs to wait after the first round of microtask execution. After all, not every async function directly returns a non-promise value or immediately resolves a Promise, so it needs to wait for an Event loop after mainline JS finishes executing

Await blocks the execution of what code

Await blocks subsequent code that is currently under the scope of async functions

When is execution of blocked code resumed?

The answer is to resume after each round of microTask execution, which round, depending on when the returned Promise is resolved

To get down to business, look at async/await

async function b() {
  console.log('1');
}

async function c() {
  console.log('7');
}

async function a() {
  console.log('2');
  await b();
  //console.log(3);
  await c();
  console.log(8);
}

a();
console.log(5);
Promise.resolve()
  .then((a)= > {
    console.log(4);
  })
  .then((a)= > {
    console.log(6);
  });

new Promise(resolve= > {
  setTimeout((a)= > resolve(), 1000);
}).then((a)= > console.log(55555555));

setTimeout((a)= > {
  console.log(123);
});
Copy the code

With the above explanation and the following GIF, the above code execution process is clear at a glance and I will not repeat it. You can see the sequence of the code step by step (using the timer, the printed information may be different from the normal execution).

conclusion

  • MacroTask or microTask is executed first

MacroTask executes first (after all, that’s how the standard is set). Why, I personally think, is it because macroTask is all about user interaction events and therefore requires a timely response

  • What does async do

    Resolve (if the return value is a Promise object, return the Promise object)

/ / verification
const p = new Promise(resolve= > resolve());
console.log(p === Promise.resolve(p)); // true
Copy the code
  • What does the await statement do

An await statement executes the following expression (in the same way if the expression is a function and an await is encountered in the function), and then blocks the code that is later in the scope of the current async function

  • When to resume execution of the code after the await statement

When an eventloop after an await statement has been executed resumes execution (it waits for the return Promise resolution to its right to complete, which may be synchronous (new Promise) or asynchronous (.then), The then callback needs to wait until the eventloop ends.)

The resources

source link
IMWeb front-end blog imweb.io/
MDN developer.mozilla.org/en-US/
Front end close reading weekly Github.com/dt-fe/weekl…
sessionstack blog.sessionstack.com/
V8 Blog FastAsync (Chinese version) V8. Js. Cn/blog/fast – a…
Tasks, microtasks, queues and schedules Jakearchibald.com/2015/tasks-…
Secrets of the JavaScript Ninja livebook.manning.com/#! / book/SEC…