微任务必须在渲染前全部执行完,其执行顺序为宏任务→全部微任务→渲染→下一个宏任务;微任务堆积会实质性推迟渲染,因主线程需连续执行完所有微任务才进入渲染;它保障DOM状态与视觉呈现的一致性,但无法强制分帧显示,需用setTimeout或requestAnimationFrame跨宏任务实现。
浏览器规范强制规定:每次宏任务结束、调用栈清空后,必须立即、连续、无中断地执行完所有已排队的微任务,之后才允许进入渲染阶段。这个顺序是硬性流程:宏任务 → 全部微任务 → 渲染 → 下一个宏任务。它不是“优先级更高”,而是被卡死在渲染门槛上——微任务不执行完,渲染就无法开始。
微任务本身不直接阻塞渲染引擎,但它的执行机制会让渲染持续等待:
queueMicrotask,主线程就得连续跑完这50个,中间不插帧、不响应鼠标、不处理新点击MutationObserver回调里又改DOM触发新一轮观察、Promise.then里无限递归调用微任务贴近渲染,核心价值不是抢时间,而是守时序:
MutationObserver必须在渲染前拿到完整的DOM变更快照,否则记录会被截断Promise.then里读offsetHeight或getBoundingClientRect(),值只有在渲染前读才是稳定可靠的同一宏任务内多次DOM修改,浏览器会合并到一次渲染中呈现。若要强制分帧显示:
setTimeout(fn, 0)把操作推到下一个宏任务requestAnimationFrame,它属于宏任务,且会在下一帧绘制前执行Promise.then——它们都在本轮微任务里,渲染仍只发生一次