关于事件循环,一道异步代码执行输出顺序问题
更多描述
setTimeout(() => {
  console.log("A");
  Promise.resolve().then(() => {
    console.log("B");
  });
}, 1000);
 
Promise.resolve().then(() => {
  console.log("C");
});
 
new Promise((resolve) => {
  console.log("D");
  resolve("");
}).then(() => {
  console.log("E");
});
 
async function sum(a, b) {
  console.log("F");
}
 
async function asyncSum(a, b) {
  await Promise.resolve();
  console.log("G");
  return Promise.resolve(a + b);
}
 
sum(3, 4);
asyncSum(3, 4);
console.log("H");Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 528
Author 回答者: shfshanyue
D F H C E G A B
Author 回答者: Echo-MakeGreatEffort
代码块的执行顺序:
- 
同步代码块:
- JavaScript 引擎会先执行所有同步代码。
 Promise.resolve()是同步执行的,而Promise.then()回调是微任务(microtask)。
 - 
宏任务和微任务:
- 宏任务(如 
setTimeout)会被放入任务队列,等到主线程空闲时才会执行。 - 微任务(如 
Promise.then()的回调)会在当前的同步代码执行完后立即执行。 
 - 宏任务(如 
 
逐步分析代码:
- 
Promise.resolve().then(() => { console.log(“C”); })
Promise.resolve()立即被执行,但then()回调被放入微任务队列。
 - 
new Promise((resolve) => { console.log(“D”); resolve(""); }).then(() => { console.log(“E”); })
- 构造函数中的代码是同步的,所以会立即执行,打印 
"D"。 resolve("")立即被调用,then()回调被放入微任务队列。
 - 构造函数中的代码是同步的,所以会立即执行,打印 
 - 
async function sum(a, b) { console.log(“F”); }
- 调用 
sum(3, 4)会立即执行函数中的同步代码,打印"F"。 
 - 调用 
 - 
async function asyncSum(a, b) { await Promise.resolve(); console.log(“G”); return Promise.resolve(a + b); }
- 调用 
asyncSum(3, 4),await Promise.resolve()会让出执行线程,console.log("G")会作为微任务被执行。 
 - 调用 
 - 
console.log(“H”)
- 这是同步代码,立即执行,打印 
"H"。 
 - 这是同步代码,立即执行,打印 
 - 
微任务队列执行:
- 微任务队列中的顺序是:
console.log("C")->console.log("E")->console.log("G")。 
 - 微任务队列中的顺序是:
 - 
setTimeout
- 宏任务在 1000ms 后执行,
setTimeout回调会被放入任务队列,在执行时先打印"A",然后执行其中的微任务Promise.resolve().then(() => { console.log("B"); })。 
 - 宏任务在 1000ms 后执行,
 
最终的输出顺序:
D
F
H
C
E
G
A
B总结:
- 同步代码先执行,打印 
"D","F","H"。 - 然后执行微任务,打印 
"C","E","G"。 - 最后,宏任务中的代码会在 1000ms 后执行,打印 
"A",随后执行其中的微任务,打印"B"。