javascript事件循环执行顺序为:先执行一个宏任务,再清空全部微任务队列(含递归新增的微任务),最后进行渲染,三者循环往复;微任务不与宏任务交替,而是在每个宏任务结束后集中、无中断地执行完毕。

JavaScript 中宏任务与微任务不是“交替”执行,而是每个宏任务结束后,立即清空全部微任务队列,再取下一个宏任务——这是事件循环的核心节奏。
宏任务先启动,微任务紧随其后
整个脚本(<script></script>)本身就是第一个宏任务。它执行完同步代码后,不会直接跳到下一个宏任务(比如 setTimeout),而是立刻检查并执行所有已排队的微任务,且一次性执行完——哪怕中间又产生新的微任务,也会继续执行,直到队列为空。
- 例如:
Promise.then、queueMicrotask、MutationObserver都属于微任务 - 它们不会“穿插”在宏任务中间执行,只会在宏任务结束后的“间隙”集中跑完
每次只取一个宏任务,但微任务全清空
宏任务队列(如 setTimeout、setInterval、I/O 回调、UI 渲染)是先进先出的,但事件循环每次只从中取出一个执行;而微任务队列没有“每次一个”的限制,只要当前宏任务结束,就全部执行完毕,不中断、不暂停。
- 哪怕你在
Promise.then里又创建了新 Promise,它的.then也会被加入当前微任务队列尾部,并在这轮中继续执行 - 这就形成了“微任务递归执行直到队列耗尽”的现象,而不是和宏任务来回切换
浏览器渲染发生在宏任务之间
在清空微任务之后、执行下一个宏任务之前,浏览器会判断是否需要更新 UI(如样式变更、DOM 修改)。这个渲染阶段不属于微任务,也不属于宏任务,而是独立环节,通常紧随微任务之后发生。
-
requestAnimationFrame是个特例:它被调度在“下次重绘前”,常被归入宏任务范畴,但实际执行时机靠近渲染阶段 - 这意味着:宏任务 → 微任务(全清空)→ 渲染 → 下一个宏任务
执行顺序可简化为三步循环
整个事件循环就是不断重复这三步:
- 执行一个宏任务(如脚本、定时器回调、事件处理函数)
- 执行所有当前微任务(无遗漏、无延迟)
- (浏览器环境)尝试渲染,然后回到第一步
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











