先看一道题,先自己看是否能做出来,有一定的难度哦。

console.log('1');

// 宏任务 A
setTimeout(() => {
  console.log('2');
  Promise.resolve().then(() => {
    console.log('3');
  });
}, 0);

async function task1() {
  console.log('4');
  await task2(); 
  console.log('5');
}

async function task2() {
  console.log('6');
  // 关键点:返回一个尚未 resolve 的 Promise
  return new Promise((resolve) => {
    // 宏任务 B
    setTimeout(() => {
      console.log('7');
      resolve();
    }, 0);
  });
}

task1();

new Promise((resolve) => {
  console.log('8');
  resolve();
}).then(() => {
  // 微任务 1
  console.log('9');
  // 宏任务 C
  setTimeout(() => {
    console.log('10');
  }, 0);
});

console.log('11');

正确答案最后揭晓。

先给出做出这道题所需要用到的知识点:

  1. 宏任务与微任务的“入队门票”
    同步代码:是第一个宏任务,永远拥有最高执行权。
    微任务 (Promise.then/await):只要被触发(Resolve),就立即进入微任务队列,在当前宏任务结束前清空。
    宏任务 (setTimeout):被调用时只是在排队,必须等前面的宏任务及其产生的微任务全部处理完,才轮到下一个。
  2. await 的“转化分水岭”
    这是最容易犯错的地方。记住你的通关公式:
await fn();
console.log('后续');

// 等价于
fn().then(() => {
  console.log('后续');
});

如果 fn() 是同步的:后续代码立即进微任务队列。
如果 fn() 包含异步(如 setTimeout):后续代码必须等那个异步操作执行完并调用 resolve 后,才会被推入微任务队列。

  1. 宏任务的“排队竞争”
    宏任务之间比的是 “谁先到达计时终点”(在 0ms 延迟下,就是比谁的代码先被执行到)。
    即便一个宏任务是在微任务里产生的(比如题中的 10),它也必须排在已经存在的宏任务队列末尾。
  2. 终极执行模型:套娃逻辑
    宏任务 A -> 执行 A -> 清空 A 产生的微任务 -> 渲染 UI -> 执行下一个宏任务 B。
    如果微任务里又产生了宏任务,它不会“插队”,而是去宏任务队列最后排队。

最后只需要记住一个中级规则,是先执行微任务,在执行宏任务,执行完一个宏任务,必须要清空他所产生的所有微任务
比如这个 3 就是紧跟2 后面的

// 宏任务 A
setTimeout(() => {
  console.log('2');
  Promise.resolve().then(() => {
    console.log('3');
  });
}, 0);

标签: none

添加新评论