大规模列表(≥10项)应使用documentfragment批量构建后一次性挂载,避免循环appendchild导致多次重排;它离屏操作、ie9+原生支持,但不可赋值innerhtml或直接插入table结构中。

直接结论:大规模列表(≥10项)别用循环 + appendChild 逐个插入,改用 DocumentFragment 批量构建再一次性挂载——它能把潜在 N 次重排压缩成 1 次,且 IE9+ 原生支持,无需 polyfill。
为什么循环appendChild插入100个li会卡顿
浏览器每次向已挂载的父节点(比如 ul)添加一个新 li,都可能触发样式计算、布局(reflow)和重绘(repaint)。尤其当父容器用了 flex、border-radius 或阴影时,开销会被放大。这不是 JS 执行慢,而是主线程反复被拉去干重活。
- DOM 节点数越多,问题越明显;50 个
li≠ 50 次轻量操作 -
DocumentFragment是离屏容器,对它的任何操作都不触发渲染——纯内存操作 - 它不是虚拟 DOM,不 diff,也不支持
querySelector或innerHTML
DocumentFragment怎么填才不报错
常见静默失败或结构错乱,往往因为误用赋值或忽略限制:
- ✅ 正确:
frag.appendChild(document.createElement('li')) - ❌ 错误:
frag.innerHTML = 'xxx'(静默失败,DocumentFragment没这个属性) - ❌ 错误:
el.innerHTML += frag(拼出[object DocumentFragment]字符串) - ⚠️ 注意:
table场景下,不能把tr直接 append 到 fragment 后再插进table;必须先 append 到tbody或thead,否则浏览器会静默修正结构
fragment 和 innerHTML 拼接,到底选哪个
不是“谁更快”的绝对问题,而是“你要保什么”:
- 要快 + 纯静态展示?
innerHTML = arr.map(x => `<li>${x}</li>`).join('')更简短,也更快(尤其结构简单) - 要绑定不同
data-id、预留click处理、后续还要改某个li的textContent?用fragment,你能拿到每个节点引用 - 内容来自用户输入?
textContent+fragment天然防 XSS;而innerHTML拼接必须手动转义,漏一处就中招 - 要保留已有
input的value、滚动位置、事件监听器?innerHTML会全毁;insertAdjacentHTML('beforeend', ...)可以,但它不走fragment路线
真正容易被忽略的点
很多人写了 fragment 却没提速,问题常出在边界上:
- 在
for循环里反复调用document.createDocumentFragment()——应该只创建一次,然后一直往里appendChild - 插入后
fragment自动清空,变量不能复用(再次appendChild什么也不会发生) - 表格分页场景下,前端切片后仍需用
fragment或innerHTML一次性写入tbody,别循环塞tr
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











