信息发布→ 登录 注册 退出

JavaScript中什么是事件循环_宏任务与微任务如何区分

发布时间:2025-12-31

点击量:
JavaScript事件循环按“宏任务→清空微任务→下一宏任务”推进;宏任务含setTimeout、script等,微任务含Promise.then、queueMicrotask等;微任务在宏任务结束后立即全量执行,故Promise.then总先于setTimeout执行。

JavaScript 的事件循环不是“等所有异步做完再执行”,而是严格按「一个宏任务 → 清空全部微任务 → 下一个宏任务」的节奏推进。理解这点,才能真正预测 setTimeoutPromise.thenqueueMicrotask 的实际执行顺序。

怎么一眼分清宏任务和微任务?看注册时机和队列归属

宏任务是事件循环的“调度单位”,每次只取一个;微任务是“插队者”,只要当前宏任务结束,立刻全量执行,不等下一个宏任务。

  • setTimeoutsetIntervalscript(整个脚本块)、UI 渲染postMessage 回调 —— 都进宏任务队列(Task Queue)
  • Promise.then/catch/finallyqueueMicrotaskMutationObserver 回调 —— 全部进微任务队列(Microtask Queue)
  • process.nextTick 是 Node.js 独有微任务,浏览器不可用;requestAnimationFrame 不是微任务,它属于宏任务,但优先级高于普通 setTimeout

为什么 Promise.then 总比 setTimeout 先执行?

因为它们不在同一个队列里,且事件循环规则强制:每个宏任务结束后,必须把当前微任务队列清空,才允许取下一个宏任务。

console.log('1');
setTimeout(() => console.log('2'), 0);
Promise.resolve().then(() => console.log('3'));
console.log('4');

输出一定是:1432。即使 setTimeout 延时为 0,它也得排队等下一轮宏任务;而 Promise.then 是微任务,在同步代码(第一个宏任务)执行完后立刻执行。

容易踩的坑:误以为 queueMicrotasksetTimeout 只差“快慢”

它们本质不是“快一点 vs 慢一点”,而是“是否让出主线程控制权”。queueMicrotask 不会让浏览器渲染或响应用户输入,适合做 DOM 批量更新前的准备;setTimeout 则明确交还控制权,浏览器可趁机重绘、处理点击事件。

  • 想在 DOM 更新后立即读取布局(如 getBoundingClientRect)?用 queueMicrotask —— 它在渲染前执行
  • 想确保 UI 已刷新、再执行后续逻辑?用 requestAnimationFramesetTimeout(后者更兼容)
  • 链式 Promise 中嵌套 setTimeout,会打断微任务连续性:一旦进入宏任务,就得等完整轮次,中间可能插入用户交互或动画帧

最常被忽略的一点:微任务队列是“动态清空”的——新微任务可在执行中产生(比如 Promise.then 里又调用 Promise.resolve().then),这些新增任务会加入当前轮次的微任务队列末尾,继续执行,直到队列彻底为空。这不是递归,是队列驱动的连续消费。

标签:# javascript  # java  # js  # node.js  # node  # 浏览器  # 点击事件  # 重绘  # 为什么  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!