什么是JavaScript事件循环_宏任务与微任务谁先执行?

14次阅读

微任务在当前宏任务结束后、下一个宏任务开始前立即清空执行,故promise.then总比setTimeout先运行;宏任务典型有setTimeout、I/O、ui渲染等,微任务典型有Promise.then、queueMicrotask、MutationObserver、process.nextTick(node.js特有,优先级最高)。

什么是JavaScript事件循环_宏任务与微任务谁先执行?

微任务在当前宏任务结束后、下一个宏任务开始前立即执行,所以 Promise.then 总是比 setTimeout 先运行。

宏任务和微任务的典型代表有哪些?

区分二者的关键不是“谁更小”,而是浏览器/Node.js引擎定义的**任务分类规则**:

  • 宏任务(macrotask):setTimeoutsetIntervalsetImmediatenode.js)、I/O 回调、UI 渲染(浏览器)、postMessage
  • 微任务(Microtask):Promise.then/catch/finallyqueueMicrotaskMutationObserver 回调、process.nextTick(Node.js,优先级高于 Promise)

注意:process.nextTick 是 Node.js 特有,它不属于标准微任务队列,但执行时机比 Promise 更早——它会在当前操作完成后、任何微任务之前执行。

事件循环中它们的执行顺序到底是怎样的?

一次完整的事件循环流程是:

立即学习Java免费学习笔记(深入)”;

  1. 执行一个宏任务(比如线程脚本、或某个 setTimeout 回调)
  2. 执行过程中遇到 Promise,其 then 被推入微任务队列;遇到 setTimeout,其回调被推入宏任务队列
  3. 当前宏任务执行完,**立刻清空整个微任务队列**(所有已排队的微任务依次执行,且新加入的微任务也会在这轮被处理)
  4. 然后才从宏任务队列取下一个任务(可能是渲染、也可能是另一个 setTimeout

这意味着:哪怕你在微任务里又创建了新的微任务,它也会被本轮执行掉,不会等到下一轮宏任务之后。

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

为什么 async/await 看起来像同步,实际还是微任务?

async 函数返回的是 Promiseawait 后面的表达式一旦 resolve,后续代码会被包装进 Promise.then —— 所以它本质仍是微任务调度。

  • await 不会阻塞线程,只是让出控制权,等 Promise settled 后再把后续逻辑排进微任务队列
  • 多个 await 链式调用,每一步 resolve 后都会触发一次微任务排队
  • 如果 await 的是普通值(非 Promise),V8 会自动包装成 Promise.resolve(value),仍走微任务流程
console.log('start'); async function foo() {   console.log('before await');   await Promise.resolve();   console.log('after await'); } foo(); console.log('end'); // 输出:start → before await → end → after await

真正容易被忽略的是:微任务队列在每次宏任务后被**完全清空**,而不是只执行一个。这个“清空”行为会让嵌套的 Promise.then 或连续的 queueMicrotask 表现出极强的连续性,甚至可能引发溢出风险(比如递归调用 queueMicrotask 却不设退出条件)。

text=ZqhQzanResources