起因:本菜鸡写的一段代码性能不好,重排重绘开销大,导师让我去改!
菜鸡代码附上
let str = '';
for(let i = 0; i < arr.length; i++){
str = `
<div class="box">
${arr[i].name}**${arr[i].age}
</div>
`;
container.innerHTML += str;
}
遍历数组生成DOM片段,插入,有其他的解决办法,但这次也让我认识了一个新的知识点:DocumentFragment
官方的解释是这样的:
DocumentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document 使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。
最常用的方法是使用文档片段作为参数(例如,任何 Node 接口类似 Node.appendChild 和 Node.insertBefore 的方法),这种情况下被添加(append)或被插入(inserted)的是片段的所有子节点, 而非片段本身。因为所有的节点会被一次插入到文档中,而这个操作仅发生一个重渲染的操作,而不是每个节点分别被插入到文档中,因为后者会发生多次重渲染的操作。
该接口在 Web 组件(Web components)中也非常有用: 元素在其 HTMLTemplateElement.content 属性中包含了一个 DocumentFragment。
可以使用document.createDocumentFragment 方法或者构造函数来创建一个空的 DocumentFragment。
//创建方式
let fragment = document.createDocumentFragment();
我将自己的菜鸡代码改成了下面这样:
//使用文档片段创建一个子树,然后再拷贝到文档中
let fragment = document.createDocumentFragment();
appendNode(fragment,arr);
//最后将文档片段添加到自己的节点上
container.appendChild(fragment);
function appendNode($node,data){
let div;
//在for循环的时候用max变量来保存长度(稍稍微微的性能优化)
for(let i = 0,max = data.length - 1;i < max ; i++){
div = document.createElement('div');
div.className = 'box';
div.appendChild(document.createTextNode(data[i].name + '**' + data[i].age));
// div.appendChild(document.createTextNode(data[i].age));
$node.appendChild(div);
}
}
总结:虽然代码量增加了几行,但是性能提高了,避免了来来回回的重排重绘!
使用DocumentFragement要比直接对DOM节点操作要快的多,而且程序员可以利用新DOM节点来操作DocumentFragement,这样比操作整个页面DOM要更容易。所以,当需要进行大量DOM操作时,尽量使用DocumentFragement,它会让你的应用变的更快!(最后一句来自别人的总结)