介绍
构建渲染树的任何改变都可能导致重绘或回流,例如:
- 添加、删除、更新
DOM
节点。 - 使用
display: none
(回流和重绘)或visibility: hidden
(仅重绘,因为没有几何形状发生变化)隐藏DOM
节点。 DOM
节点的移动和动画。- 添加样式表或调整样式属性。
- 用户操作,例如调整窗口大小、更改字体大小或滚动页面。
以前我们可以使用节点的 cloneNode()
方法,在克隆的节点上进行操作,然后再用克隆的节点替换原始节点来优化性能,而现在我们可以使用 DocumentFragment
。
DocumentFragment
(文档片段),与 document
一样,没有父节点,存储由节点(Node
)组成的文档结构。但它不是主 DOM
树的一部分,它的变化不会触发 DOM
树的重新渲染,且不会对性能产生影响。
因为文档片段存在于内存中,并不在 DOM
树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来 更好的性能。
使用
文档片段接口没有特定属性和方法,都继承自其父接口 Node
。
最常用的方法是使用 DocumentFragment
创建并组成一个 DOM
子树,然后将其插入到 DOM
中。这种情况下会插入片段的所有子节点,并留下一个空的 DocumentFragment
。因为所有的节点会被一次插入到文档中,所以仅会发生一个重渲染的操作,而不是每个节点分别被插入到文档中从而发生多次重渲染的操作。
该接口在 Web
组件(Web components
)中也非常有用:<template>
元素在其 HTMLTemplateElement.content
属性中包含了一个 DocumentFragment
。
可以使用 document.createDocumentFragment
方法或者构造函数 new DocumentFragment()
来创建一个空的 DocumentFragment
。
1 | let fragement = document.createDocumentFragment(); |
示例
比如,我们要在一个列表中插入 10000
个节点:
1 | <button onclick="myFunction()">document</button> |
一个个的插入到 DOM
,并计算所用时间:
1 | function myFunction() { |
先把所有节点添加到 DocumentFragment
,然后一次性插入 DOM
,并计算所用时间:
1 | function myFunction2() { |
可以看到使用 DocumentFragment
在处理大批量 DOM
操作时,可以节省很大的性能,在 DOM
操作越多时,这种优势越明显。