5月27日 23:25

Promise 微任务什么时候执行?事件循环怎么跑的?

面试常问这道题,本质是在考察你对 JS 异步执行顺序的理解。核心答案:微任务在当前宏任务结束后、下一个宏任务开始前全部执行完毕;Promise 的 then/catch/finally 回调属于微任务,会在所有同步代码之后、setTimeout 之前执行。

事件循环的执行顺序

记住这个流程就够了:

  1. 执行同步代码(调用栈)
  2. 清空微任务队列(全部执行)
  3. 取一个宏任务执行
  4. 回到步骤 2,循环往复

所以微任务不是"尽快执行",而是"在当前宏任务结束后立即执行"。这是理解所有输出顺序题的根基。

微任务和宏任务有哪些

微任务:Promise.then/catch/finally、queueMicrotask()、MutationObserver、async/await 中 await 后面的代码。

宏任务:setTimeout、setInterval、setImmediate(Node)、I/O、UI 渲染。

经典输出顺序题

javascript
console.log("1"); setTimeout(() => console.log("2"), 0); Promise.resolve().then(() => console.log("3")); console.log("4"); // 输出:1 → 4 → 3 → 2

同步代码先跑(1、4),然后清空微任务(3),最后执行宏任务(2)。

链式 then 的执行顺序

javascript
Promise.resolve() .then(() => console.log("1")) .then(() => console.log("2")) .then(() => console.log("3")); Promise.resolve() .then(() => console.log("4")) .then(() => console.log("5")); // 输出:1 → 4 → 2 → 5 → 3

每个 then 返回新 Promise,下一个 then 注册为该 Promise 的微任务。两根链条交替推进,按注册顺序轮流执行。

嵌套 Promise 怎么跑

javascript
Promise.resolve() .then(() => { console.log("1"); Promise.resolve().then(() => console.log("2")); }) .then(() => console.log("3")); // 输出:1 → 2 → 3

第一个 then 执行时注册了内层微任务,外层第二个 then 也在此时被注册。当前微任务轮次里,两个微任务都已入队,按先进先出执行:先 2 后 3。

async/await 和微任务的关系

javascript
async function foo() { console.log("1"); await bar(); console.log("2"); // 这行是微任务 } function bar() { console.log("3"); } foo(); console.log("4"); // 输出:1 → 3 → 4 → 2

await 后面的代码等价于放到 then 回调里,是微任务。这是 async/await 的本质——语法糖。

Node.js 的差异

Node.js 中 process.nextTick 优先级比 Promise.then 更高,会先于微任务队列执行。另外 Node 11 之后,每个宏任务结束后也会清空微任务,行为已与浏览器一致。

追问:微任务会阻塞渲染吗

会。微任务在渲染前执行,如果微任务队列过长,页面就会卡住。所以不要在微任务里做密集计算,该用 setTimeout 让出主线程时就用。

标签:Promise