使用文档片段真的可以提高性能吗?

Sam*_*Ccp 36 javascript performance documentfragment

我对JS的性能有疑问.

说,我有下一个代码:

var divContainer = document.createElement("div"); divContainer.id="container";
var divHeader = document.createElement("div"); divHeader.id="header";
var divData = document.createElement("div"); divData.id="data";
var divFooter = document.createElement("div"); divFooter.id="footer";
divContainer.appendChild( divHeader );
divContainer.appendChild( divData );
divContainer.appendChild( divFooter );
document.getElementById("someElement").appendChild( divContainer );
Run Code Online (Sandbox Code Playgroud)

这段代码只为其他一些函数创建了一个shell来创建一个网格,创建网格的过程非常复杂,并且有很多验证,目前我用2种方法填充网格,一个在数组变量中创建整个html另一个创建元素并将它们附加到一个元素documentFragment.

我的问题是,当我使用片段时,如果在使用片段时性能确实有所改善 - 他们管理内存中的元素,因此它们不会附加到文档中,因此不会触发DOM重新计算和其他令人讨厌的东西.但是我创建变量的方式是,在将容器附加到实际页面之前,它们不会附加到任何DOM元素.

所以我想知道以前的代码是否比使用包装它的文档片段具有更好的性能:

var fragment = document.createDocumentFragment();
var divContainer = document.createElement("div"); divContainer.id="container";
var divHeader = document.createElement("div"); divHeader.id="header";
var divData = document.createElement("div"); divData.id="data";
var divFooter = document.createElement("div"); divFooter.id="footer";
divContainer.appendChild( divHeader );
divContainer.appendChild( divData );
divContainer.appendChild( divFooter );
fragment.appendChild( divContainer )
document.getElementById("someElement").appendChild( fragment.cloneNode(true) );
Run Code Online (Sandbox Code Playgroud)

正如我已经说过的,这是一个关于性能的问题,我知道作为一种最佳实践,建议使用片段,但是我无法想到这样做,这样做只会在内存中创建一个新对象,什么都不做,所以我假设在这种情况下放弃片段是有效的.

希望有些js guru/god会在这里发出希望之光并帮助我们解决这个问题.


编辑:所以,我一直在寻找与此问题相关的内容,似乎documentFragments并不一定意味着更好的性能.

它只是节点的"内存"容器.片段之间的区别,比如a <div>,片段没有父节点,它永远不会在DOM上,只在内存中,这意味着片段上的操作更快,因为没有DOM的操作.

W3C关于documentFragments的文档非常模糊,但重要的是,每个人最喜欢的浏览器都没有使用真正的片段,而是根据这个MSDN文档创建了一个新文档.这意味着,IE上的片段速度较慢.

所以,问题占上风,如果我在变量中创建一个元素(<div>例如)但是不要将它附加到DOM,添加元素(div,表等)和东西,并且在完成所有工作之后(循环,验证,元素的样式),附加该元素,它是否与片段相同?

考虑到IE使用"假"片段的事实我至少在IE中使用这种方法(使用像div这样的元素,而不是片段)更好,我真的不关心IE但我需要测试它(办公室的政策).

另外,如果我在数组上创建所有html,如下所示:

var arrHTML = ["<table>","<tr>", ....]; 
Run Code Online (Sandbox Code Playgroud)

然后这样做

document.getElementById("someElement").innerHTML = arrHTML.join(""); 
Run Code Online (Sandbox Code Playgroud)

它在IE上更快,但其他主流浏览器(FF,Chrome,Safari和Opera)在使用容器然后附加它(片段或div)时表现更好.

所有这一切都是因为创建所有元素的过程非常快,大约需要8到10秒才能创建多达20,000行24列,这是很多元素/标签,但浏览器似乎冻结了几秒钟如果我一个接一个地追加它们,那么它们都会立即附加,这就是地狱.

再次感谢大家,这真的很有趣也很有趣.

wol*_*m77 26

文档片段更快,当它被用来插入一组元素多个地方.这里的大多数答案指出它没有效用,但这是为了展示它的力量.

让我们举个例子.

假设我们需要使用类容器10个元素中追加20个div.

无:

var elements = [];
for(var i=20; i--;) elements.push(document.createElement("div"));

var e = document.getElementsByClassName("container");
for(var i=e.length; i--;) {
  for(var j=20; j--;) e[i].appendChild(elements[j].cloneNode(true));
}
Run Code Online (Sandbox Code Playgroud)


附:

var frag = document.createDocumentFragment();
for(var i=20; i--;) frag.appendChild(document.createElement("div"));

var e = document.getElementsByClassName("container");
for(var i=e.length; i--;) e[i].appendChild(frag.cloneNode(true));
Run Code Online (Sandbox Code Playgroud)

对我来说,使用文档片段在Chrome 48上的速度提高了16倍.

测试JsPerf

  • **这是最好的答案.**虽然这里的jsPerf测试没有包含页面重排(避免页面重排是使用DocumentFragments的主要好处),但它确实说明了使用DocumentFragments避免DOM遍历的真正性能提升.DocumentFragment代码的执行速度是Chrome 48中非片段代码的2倍,在IE11中快4倍.如果您是构建使用JavaScript动态呈现的页面的开发人员,那么这就是您使用DocumentFragments的原因. (2认同)

Snu*_*gus 10

通常,您希望使用片段来避免重排(重新绘制页面).一个很好的例子是,如果你循环一些东西并在循环中追加,但是,我认为现代浏览器已经优化了这一点.

我设置了一个jsPerf来说明何时在这里使用片段的一个很好的例子.你会注意到在Chrome中几乎没有差别(我认为工作中的现代优化),然而,在IE7中,我得到的是没有片段的.08 ops/sec,带有片段的3.28 ops/sec.

因此,如果您循环遍历大型数据集并附加大量元素,请使用片段,这样您只需要一次重排.如果你只是几次附加到dom,或者你只是针对现代浏览器,则没有必要.


Nic*_*tti 6

我已经编写了一个jspref来测试它,看起来节点片段的速度提高了2.34%

http://jsperf.com/document-fragment-test-peluchetti

  • 感谢您的支持,用 firefox 和 safari 进行测试都表明,不使用片段要快得多,IE ( 8 ) 就会死掉。但问题仍然存在,使用片段真的比仅将一个元素(其中包含子元素,如示例)附加到 DOM 具有更好的性能吗? (2认同)
  • @SamCcp 这个 jsPerf 测试有缺陷。DocumentFragments 的重点是避免昂贵的页面 *reflows* 和/或 DOM 遍历。这个 jsPerf 测试既不包含。jsPerf 测试执行的 DOM 操作不可见,并且没有页面重排。 (2认同)