Understanding of asynchronous macro and micro tasks and the execution order of promise async settimeout

Keywords: Javascript Front-end

During the interview, you will inevitably encounter the problem of asynchronous execution sequence. Let's have a look. Content continuously updated ~

Asynchronous and synchronous concepts

javascript language is a "single thread" language. Operations that can change the normal execution order of programs can be regarded as asynchronous operations.
Summary: synchronous blocking process, asynchronous does not need to wait.

//Asynchronous setTimeout
setTimeout(function () {
            console.log('5');
        }, 10000)
console.log('8');
The normal understanding here is to execute 5 first and then 8, but we can't wait 10 seconds to execute 5 and then 8.     
Because of the settimeout It is asynchronous operation. We can execute 8 first and then 5.

So how does the system understand that when executing code, the browser will default that setTimeout and ajax request methods are time-consuming programs. By default, they are added to a queue dedicated to storing time-consuming programs. Only when all non time-consuming programs are executed, can the programs in this queue be executed.

Synchronization is the execution of one thing. The next task can only be executed after the previous task has been executed.
Asynchronous does not need to wait for the previous task to complete.

What asynchrony does js have

Execute in the order you expect and return the expected results
1. Timer
2. Event binding
3. Publish / subscribe mode
4. Callback function
5.ajax
6.promise
7.async await

timer

setTimeout(function(){
console.log('1');

    },3000)
    setTimeout(function(){
        console.log('2');
    },2000) 
console.log('3');//3,2,1

Event binding

Use event driven. This idea means that the execution of asynchronous tasks does not depend on the order of code, but on whether an event occurs.
For example, an event is triggered when you click a button.

Publish / subscribe mode (observer mode)

In the publish / subscribe mode, you can imagine that there is a message center where you can "register a message". Then the registered message can be "subscribed" by several interested people. Once the "message is published" in the future, all those who subscribe to the message will be reminded.

Callback function

Callback function: take callback function A as the parameter of B function and execute it inside B function; Then execute B first and then A.
But there's a problem with hell
Callback hell refers to the multi-level nesting between callback functions.

//Function 1:
function stretch oneself(x){
    console.log('stretch oneself');
    x(get up)//Execute the dressed function
}
//Function 2:
function dress(x){
    console.log('dress');
    x()//Function to execute
}
//Function 3:
function get up(){
    console.log('get up');
}
//Start function execution
 stretch oneself(dress);
//Execution results stretch, dress and get up

No matter how you change the order of function 1, function 2 and function 3, the execution result is always stretching, getting dressed, getting up, and always executing in the order you expect to get up. However, when there are multiple functions, the logic becomes unclear and the code is difficult to write or maintain. We call it callback hell.

ajax

Both static websites and dynamic websites are synchronized, but the synchronization method has disadvantages: page request response blocking, which affects the user experience
In order to solve this problem, we can use flexible means to realize the local update of the page (hidden frame). Ajax is available because the hidden frame is inconvenient

promise

And in the order you want,
1. It is mainly used for asynchronous computing
2. You can queue asynchronous operations, execute them in the desired order, and return the expected results
3. promise can be passed and manipulated between objects to help us deal with queues

What is promise

ES6 provides a solution to asynchronous programming, which is an object itself

What can promise do

To solve callback hell, asynchronous code is written synchronously

promise three states

Promise has three statuses: pending, resolve and reject

Pros and cons of Promise

Asynchronous operations can be expressed in the process of synchronous operations, avoiding layers of nested callback functions. In addition, Promise objects provide a unified interface, making it easier to control asynchronous operations.
Promise cannot be cancelled. Once it is created, it will be executed immediately. It cannot be cancelled halfway. Secondly, if the callback function is not set, the errors thrown by promise will not be reflected to the outside. Third, when it is in the pending state, it is impossible to know which stage it has reached (just started or about to be completed).

var p = new Promise((resolve, reject) => {
 console.log("1");
 resolve("2"); 
});
 
p.then((value) => {
 console.log(value);
}) 

console.log("4");// 1 4 2 instead of 124

promise chained call

let p = new Promise(step1)
function step1(resolve,reject){
setTimeout(function(){
        var a = 1
        resolve(a)
    },1000)
}
function step2(resolve,reject){

setTimeout(function(){
        var b = 2
        resolve(b)
    },3000)
}
function step3(resolve,reject){
setTimeout(function(){
        var c = 3
        resolve(c)
    },2000)
}

p.then((data)=>{
    console.log(data);
    return new Promise(step3)
}).then(data=>{
    console.log(data);
    return new Promise(step2)
}).then(data=>{
    console.log(data);
})
// Execute step1, step3 and step2 in sequence, and the result is 1, 3 and 2

async await

async is equivalent to promise. The statement on the right of await waits for the completion of the statement before executing. The statement after await is equivalent to then.

async function fn(){//Promise is generated here
  console.log(1)
  await fn1() //Start generating then
  console.log(2)
}
async function fn1(){
  console.log(3)
  await fn2()
  console.log(4)
}
function fn2(){
  console.log(5)
}
fn() 
console.log(6)

Execute first scrpit Synchronization tasks under fn();
implement fn(),Print'1',
encounter fn1(),Print'3',take'2'Put it into the task queue;
encounter fn2(),Print'5',take'4'Put in task queue
 Direct printing'6';
Now start processing the queue:
wait for fn1()Execute after all are executed'2',
So print first'4',Reprint'2'
The sequence is 1 3 5 6 4 2 


Asynchronous implementation principle (event loop)

Through the event loop, you understand the event loop mechanism and the JS execution mechanism

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

console.log(1) It's a synchronization task,Put it in the main process
setTimeout() Asynchronous task,Put in event table, 0 Pushed in seconds event queue in
console.log(3) It's a synchronization task,Put it in the main route
 When 1 and 3 are printed on the control bar,Main thread to event queue(Event queue)Check whether there are executable functions in the,
implement setTimeout Function in

Macro and micro tasks

Macro task: including overall code script, setTimeout and setInterval
Micro task: Promise, process.nextTick
In the event loop mechanism:
The first round of macro task executes script, and then starts to execute all micro tasks
Then execute the second round of macro task settimeout
Note that async function is still based on Promise encapsulation, and Promise is a kind of micro task; Therefore, all the code after await async2() will be put into the then callback function of Promise.

Execution sequence summary:

The code is executed from top to bottom,
Whenever an external code is encountered, it is macro task 1. Macro task 1 is the first round of macro tasks and is executed directly,
Whenever setTimeout is encountered, macro task 2 is the second round of macro tasks. Macro task 2 should be executed after all micro tasks are completed and placed in the macro task queue
Whenever a new promise is encountered, the code in then is a micro task and placed in the micro task queue,
async code is executed directly
The code on the right side of await is executed directly
The code behind await is equivalent to then, which is put into the micro task.

case

setTimeout(() => {
//Callback a macro event after execution
    console.log('Inner macro event 3')
}, 0)
console.log('Outer macro event 1');

new Promise((resolve) => {
    console.log('Outer macro event 2');
    resolve()
}).then(() => {
    console.log('Micro event 1');
}).then(()=>{
    console.log('Micro event 2')
})
Outer macro event 1
 Outer macro event 2
 Micro event 1
 Micro event 2
 Inner macro event 3
• First, the browser executes js Enter the first macro task and enter the main thread, encounter setTimeout  Distribute to macro task Event Queue in

• encounter console.log() Direct execution output macro event 1

• encounter Promise, new Promise Directly execute output macro event 2

• implement then Distributed to micro tasks Event Queue in

•The first round of macro task execution ends and micro task printing starts 'Micro event 1' 'Micro event 2'

•After the execution of the first round of micro tasks, execute the second round of macro events and print setTimeout Inside content'Inner macro event 3'
setTimeout(function(){
 console.log('The timer starts')
 });
 
 new Promise(function(resolve){
     console.log('Execute now for Cycle');
     for(var i = 0; i < 10000; i++){
         i == 99 && resolve();
     }
 }).then(function(){
     console.log('implement then Function')
 });

console.log('End of code execution');
 
Execute first script Macro tasks under,encounter setTimeout,Put it in the [queue] of the macro task

encounter new Promise Direct execution,Print"Execute now for Cycle"

encounter then method,It's a micro task,Put it in the [queue] of the micro task

Print "End of code execution"

This round of macro task has been executed,View the current round of micro tasks,Found one then Function in method, Print"implement then Function"

Here we are,Current round event loop All done.

In the next cycle,Execute a macro task first,It is found that there is one in the [queue] of the macro task setTimeout Function in,
Execute printing"The timer starts"
console.time('start');

setTimeout(function() {
  console.log(2);
}, 10);

setImmediate(function() {
  console.log(1);
});

new Promise(function(resolve) {
  console.log(3);
  resolve();
  console.log(4);
}).then(function() {
  console.log(5);
  console.timeEnd('start')
});

console.log(6);

process.nextTick(function() {
  console.log(7);
});

console.log(8);
script(Main program code)->process.nextTick->promise->setTimeout->setImmediate
 Body part: definition promise The construction part of is synchronous, so 3 and 4 are output first,
The main part outputs 6 and 8 (in the case of synchronization, it is in strict accordance with the defined order)
process.nextTick: Output 7
promise:  there promise Part, strictly speaking, is promise.then part,
The output is 5, and timeEnd('start')
setImmediate: Output 1. According to the above priority, it should be output first setTimeout,
But notice, setTimeout Set 10 ms delayed
setTimeout :  Output 2
 The execution sequence of the synthesis is: 3——>4->6->8->7->5->start: 7.009ms->1->2
// 41368275
    /*
    aysnc And promise are synchronous tasks, which are executed in sequence, but aysnc returns the promise object
    Synchronization is performed in sequence, 4 - > async1() - > 6 - > 8
    Execute async1(): 4 - > 1 - > async2(), that is, 3 - > 6 - > 8
    Perform all micro tasks, i.e. then, 4 1 3 6 8 2 7
    Execute the second round of macro tasks, i.e. settimeout 4 1 3 6 8 2 7 5

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

Posted by yanjchan on Wed, 20 Oct 2021 23:09:22 -0700