Execution order of async/await, promise and setTimeout (latest in 2023)

Start with a topic

I saw an interview question today about the execution order of async/await, promise and setTimeout . The question is as follows:

async function async1() {
	console.log('async1 start');
	await async2();
	console.log('asnyc1 end');
}
async function async2() {
	console.log('async2');
}
console.log('script start');
setTimeout(() => {
	console.log('setTimeOut');
}, 0);
async1();
new Promise(function (reslove) {
	console.log('promise1');
	reslove();
}).then(function () {
	console.log('promise2');
})
console.log('script end');

 The answer I gave:

script start
async1 start
async2
asnyc1 end // x
promise1
script end
promise2
setTimeOut

Correct answer:

script start
async1 start
async2
promise1
script end
asnyc1 end
promise2
setTimeOut

Why does promise1 come out before asnyc1 end? With this question, I went to learn about the event loop mechanism.

js EventLoop event loop mechanism

There are two types of events in JavaScript: 

 The execution sequence of events is to execute macro tasks first, and then execute micro tasks. This is the basis. Tasks can have synchronous tasks and asynchronous tasks. The synchronous ones enter the main thread, and the asynchronous ones enter the Event Table and register the function. After the asynchronous event is completed, it will Put the callback function into the Event Queue (macro tasks and micro tasks are different Event Queues). After the synchronization task is executed, the events will be read from the Event Queue and put into the main thread for execution. The callback function may also contain different task, so the above operations are performed in a loop.

Note: setTimeOut does not directly put your callback function into the above-mentioned asynchronous queue, but puts the callback function into the execution asynchronous queue after the timer time is up. If there are already many tasks in this queue at this time, then queue them behind them. This also explains why setTimeOut cannot be executed accurately. The execution of setTimeOut needs to meet two conditions:

The main process must be idle. If the time is up, the main process will not execute your callback function if it is not idle.
This callback function will not be executed until all the previous asynchronous functions have been executed when it is inserted into the asynchronous queue.

promise、async/await

First of all, new Promise is a synchronous task and will be placed in the main process for immediate execution. The .then() function means that asynchronous tasks will be placed in the asynchronous queue. When will they be placed in the asynchronous queue? When your promise state ends, it will be immediately put into the asynchronous queue.

Functions with the async keyword will return a promise object . If there is no await in it, the execution is equivalent to an ordinary function; if there is no await, the async function is not very powerful, right?

The await keyword must be inside the async keyword function. If await is written outside, an error will be reported; await, like its semantics, is waiting for the expression on the right to complete. At this time, await will leave the thread, block subsequent code within async, and execute code outside async first. The subsequent code inside will not be executed until the outer synchronization code is executed. Even if await is not a promise object but a synchronized function, it will still wait for this operation.

Process sorting

Let’s review the execution process of the above code as a whole: 

  1. The entire code snippet (script) executes console.log('script start') as a macro task and outputs script start;
  2. Executing setTimeout is an asynchronous action and is placed in the macro task asynchronous queue;
  3. Execute async1(), output async1 start, and continue executing;
  4. Execute async2(), output async2, and return a promise object. await gives up the thread and adds the returned promise to the microtask asynchronous queue, so the code below async1() must also wait for the above to complete before continuing to execute;
  5. Execute new Promise, output promise1, and then put resolve() into the microtask asynchronous queue;
  6. Execute console.log('script end') and output script end;
  7. At this point, all synchronized codes have been executed, and then go to the microtask asynchronous queue to obtain the task.
  8. Next, resolve (returned by the promise returned by async2) is executed, and async1 end is output;
  9. Then execute resolve (new Promise) and output promise2;
  10. Finally, setTimeout is executed and settimeout is output. 

In step 4, there is a mechanism for await, which is await's waiting, which will not block the execution of external functions. If await is waiting for a Promise, the code in the Promise will still be executed synchronously. If it is not a Promise, Promise will be used. .resolve to encapsulate, async2 here is an async method, the printing inside will be executed synchronously, and the code after await async2() will be placed at the first position in the microtask queue, waiting for the external synchronization code to be executed. implement.

So I know why script end outputs priority over async1 end.

Guess you like

Origin blog.csdn.net/YN2000609/article/details/132409910