需用 raf 配合 documentfragment:fragment 合并 dom 操作消除中间重排,raf 将插入时机对齐浏览器下一帧,避免阻塞主线程或强制同步布局;仅 fragment 不足,因其插入仍是同步的,可能挤占滚动/动画帧。

用 document.createDocumentFragment 配合 requestAnimationFrame(rAF),不是简单“叠加两个优化”,而是分阶段控制渲染节奏:Fragment 负责合并 DOM 操作、消除中间重排,rAF 则把最终插入时机交给浏览器渲染帧的空闲起点,避免阻塞当前帧或触发强制同步布局。关键在于两者分工明确——Fragment 做“内容打包”,rAF 做“插入择时”。
为什么需要 rAF,光靠 Fragment 不够?
Fragment 确实把 100 次插入压缩成 1 次 DOM 操作,但若这 1 次插入发生在 JS 执行中段(比如用户滚动或动画进行时),仍可能挤占主线程、导致掉帧。rAF 的作用是告诉浏览器:“请在我下一帧绘制前执行这个插入”,让 DOM 更新与屏幕刷新对齐,提升视觉流畅度。
- 直接
container.appendChild(fragment)是同步操作,立刻触发 layout;放在 rAF 回调里,则排队等待下一帧,浏览器可统筹安排样式计算、布局、绘制 - 特别适合在 scroll、resize、input 等高频事件中批量更新 UI,避免因 DOM 插入拖慢响应
- 注意:rAF 不是异步延迟,它不保证执行时间精确到毫秒,只承诺“在下一次重绘前”
正确组合写法:先建 fragment,再用 rAF 插入
不能在 rAF 回调里反复创建 fragment(会破坏批量意义),也不能把整个循环塞进 rAF(rAF 回调应轻量)。标准流程是:数据处理 → 构建 fragment(同步、离线)→ rAF 中仅做 final append。
- 先同步完成所有节点创建和 fragment 组装,不涉及真实 DOM,无性能负担
- rAF 回调体里只写一行:
container.appendChild(fragment),不加其他逻辑 - 如果需多次批量更新(如分页加载),每次都要新建 fragment,不可复用已插入过的 fragment
实际场景示例:滚动中动态追加列表项
比如实现“滚动到底部加载更多”,既要防重复触发,又要保证插入不卡顿:
- 监听
scroll,用节流判断是否触底 - 获取新数据后,用循环 +
createElement构建全部li,全部appendChild到新创建的 fragment - 在 rAF 回调中执行
listEl.appendChild(fragment),确保插入不打断当前滚动动画 - 避免在 rAF 里读取
offsetHeight或getComputedStyle,防止强制回流抵消优化效果
什么情况不必加 rAF?
rAF 增加了一帧延迟,不是万能补丁。以下情形直接用 fragment 即可,无需 rAF:
- 页面初始化时一次性渲染(如首屏列表),没有实时交互动机
- 插入操作本身不频繁(比如每秒最多几次),且不在敏感交互路径中
- 目标容器尚未挂载(如还在 documentFragment 或未 appendTo body 的节点),此时插入本就不触发重排
- 使用了
innerHTML字符串拼接且结构简单,其内部优化已足够快,加 rAF 反而增加调度开销










