event loop 不处理渲染,而是为渲染留出明确时机;dom 渲染是浏览器在微任务清空后、下一个宏任务开始前主动触发的检查与绘制过程,非队列任务。

Event Loop 不“处理”渲染,而是为渲染留出明确时机;DOM 渲染本身不是任务队列里的某类任务,而是一个由浏览器主动触发的、固定位置的检查与绘制过程——它发生在每次微任务清空之后、下一个宏任务开始之前。
微任务一定在渲染前执行
只要 DOM 被 JavaScript 修改(比如 innerHTML、classList 或 style 变更),这些变更会立即生效到 DOM 树和 CSSOM,但不会立刻显示在屏幕上。浏览器要等到当前宏任务结束、所有已排队的微任务(Promise.then、queueMicrotask、MutationObserver)全部执行完毕后,才进入渲染判断阶段。
- 你在 Promise 回调里读取 offsetHeight,很可能拿到旧值,因为样式计算和布局还没发生
- 连续多次修改同一个元素的 className,只有最后一次会参与本次渲染,中间状态被合并或丢弃
- 用 MutationObserver 监听 DOM 变化时,回调属于微任务,因此总在渲染前触发
渲染不是任务,但有固定插入点
浏览器没有把“paint”或“composite”放进宏任务或微任务队列。它是在每轮 Event Loop 的特定节点——微任务队列清空后、下个宏任务取出前——主动检查:是否有样式变更、布局变动、动画帧请求(如 rAF)、或 visibility 等影响视觉输出的因素。有则渲染,无则跳过。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 这意味着 setTimeout(fn, 0) 的回调一定在渲染之后执行,哪怕只延迟 0 毫秒
- alert()、confirm() 这类同步阻塞操作会暂停整个主线程,包括渲染时机,所以弹窗期间页面完全冻结
- 强制重排(如读 offsetTop)会提前触发布局计算,但不等于触发渲染;渲染仍要等那个固定检查点
requestAnimationFrame 是渲染前的“最后一刻钩子”
rAF 回调既不进宏任务队列,也不进微任务队列。它由浏览器在决定渲染前、布局和绘制步骤开始前统一调用,且每帧最多执行一次。它是唯一能稳定拿到“即将渲染前最新 DOM 状态”的机制。
- 适合做动画关键帧计算、滚动位置采样、避免 layout thrashing
- 比 Promise.then 更接近视觉更新,但比直接同步操作稍晚——刚好卡在渲染流水线入口
- 多个 rAF 注册会合并到同一帧,不会重复触发
实际开发中要注意的典型误区
很多“DOM 更新没立刻生效”的困惑,本质是混淆了 DOM 变更、样式计算、布局、绘制、合成这几个阶段,误以为改完 innerHTML 就等于画面刷新。
- 不要依赖微任务里读取 clientWidth/offsetHeight 做逻辑判断,除非你明确知道此时 layout 已完成(通常需额外强制触发)
- 批量 DOM 操作尽量用 documentFragment 或一次性 innerHTML 替代多次 appendChild,减少不必要的样式重计算
- 需要确保用户看到变化?用 rAF 包裹读取逻辑;需要确保逻辑基于最新 DOM?微任务足够;需要跨帧协调?组合 rAF + Promise
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










