javascript中宏任务与微任务的切换由事件循环自动调度:每个宏任务执行完后立即清空全部微任务队列,再取下一个宏任务;浏览器在微任务清空后、下个宏任务前渲染;node.js中process.nexttick优先级高于promise微任务。

JavaScript 中宏任务与微任务的切换不是由开发者手动“管理”的,而是由事件循环(Event Loop)自动、严格调度的。你无法主动暂停、跳过或重排它们的执行顺序,但可以通过理解规则来预判行为、避免陷阱。
切换发生在每个宏任务结束之后
事件循环每次只取一个宏任务执行;一旦该宏任务的同步代码运行完毕(即调用栈清空),引擎立刻暂停宏任务流程,转向检查并**一次性清空整个微任务队列**——不管队列里是 1 个还是 100 个微任务,都会连续执行,中间不插入任何宏任务。
- 哪怕在微任务执行过程中又产生了新微任务(比如
Promise.then里再链一个.then),它也会被追加到当前微任务队列末尾,并继续执行,直到队列彻底为空。 - 只有微任务队列完全清空后,事件循环才会回到宏任务队列,取出下一个宏任务(如 setTimeout 回调)开始新一轮循环。
浏览器渲染插在宏任务之间
在浏览器环境中,微任务清空后、下一个宏任务开始前,引擎会判断是否需要更新 UI。如果 DOM 有变更且处于合适时机,就会触发一次渲染(paint/reflow)。这意味着:
-
requestAnimationFrame是个特殊宏任务,它会在**下次渲染前**执行,优先级高于普通 setTimeout,但低于微任务。 - 连续多次修改 DOM 后,只要没触发新的宏任务,所有变更都等微任务跑完、渲染阶段统一处理——这正是 Vue/React 批量更新的基础。
Node.js 有额外层级:process.nextTick
Node.js 的事件循环比浏览器更细粒度,process.nextTick 的优先级高于 Promise 微任务,它会在当前操作(哪怕还在同一个宏任务内)结束后、任何微任务之前立即执行:
- 它不属于标准微任务队列,而是 Node 特有的“next tick 队列”,在每个事件循环阶段切换前强制清空。
- 滥用
nextTick可能导致 I/O 饥饿(阻塞其他阶段),一般只用于底层库的错误边界或紧急回调。
常见误判点:嵌套不会改变优先级
宏任务里创建微任务,或微任务里再创建宏任务,都不会提升后者优先级:
-
setTimeout(() => { Promise.resolve().then(...); }, 0):外层是宏任务,内层 Promise 是它的微任务——但它仍属于“这个 setTimeout 宏任务执行完后才轮到”的那一波微任务,不会插队到当前正在执行的宏任务之后。 -
Promise.resolve().then(() => setTimeout(...)):微任务里扔出的 setTimeout,只能排到所有当前微任务跑完、下一轮宏任务队列的末尾。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











