为什么分离和添加比直接更改HTML更有效?

3

我听说在将多个元素插入DOM时,先分离目标元素,然后插入元素,最后再将其附加回DOM会更有效率。我想知道为什么。

例如,

html

<div id="main">
  <ul class="list"></ul>
</div>

jQuery

var arrayOfElements = [$("<li> .... </li>"), $("<li> .... </li>"), ... , $("<li> ... </li>")]

# Appraoch 1
$(".list").html(arrayOfElements);

# Approach 2
$(".list").detach().html(arrayOfElements).appendTo(".main");

为什么方法二更有效,并且其效率提升的显著程度是多少?

你尝试过这样做吗?这可能是因为这样可以确保只有一个文档重新排版。 - Alnitak
2
需要先使用join()函数来连接字符串数组才能正常工作。请自行运行性能测试以找出最佳解决方案 http://jsperf.com - charlietfl
@charlietfl 我已将字符串更改为JQuery对象。这样可以吗?好的,我会运行性能测试。但我仍然想知道为什么一个比另一个更有效率。 - mc9
1个回答

5
当向DOM添加一系列元素时,每个元素都会触发浏览器重新排版页面。将已经准备好但尚未在DOM中的一个元素添加到DOM中只会导致页面重新排版一次。
引自:http://www-archive.mozilla.org/newlayout/doc/reflow.html 所有重新排版都有一个原因,该原因保存在重新排版状态对象中(并且可能会变异,如下所述)。重新排版原因控制帧在重新排版期间的反应,并且是以下之一:
文章继续列出了重新排版的原因,以下是其中之一:
当帧树中的某些内容发生更改时(例如,从网络读取更多内容或某些脚本操作DOM),就会出现增量式重新排版。增量式重新排版针对帧层次结构中的单个帧。在增量式重新排版期间,帧可以假定从上面计算出的约束条件(例如,可用宽度)没有更改;相反,帧内部发生了更改,这可能会对帧层次结构产生自下而上的影响。
至于性能改进,我将留给John Resig。
Browser         Normal (ms) Fragment (ms)
Firefox 3.0.1   90          47
Safari  3.1.2   156         44
Opera 9.51      208         95
IE 6            401         140
IE 7            230         61
IE 8b1          120         40

来源: http://ejohn.org/blog/dom-documentfragments/

不过,你的示例有些缺陷。

var arrayOfElements = [$("<li>....</li>"), $("<li>....</li>"), $("<li>...</li>")];

应该写成:
var arrayOfElements = ["<li>....</li>", "<li>....</li>", "<li>....</li>"].join('');

其次
// Approach 1
$(".list").html(arrayOfElements);

在这两个例子中,这一个可能更好。为什么呢?

因为:

// Approach 2
$(".list").detach().html(arrayOfElements).appendTo("#main");

可能会导致最多(并且很可能会)2次回流。一次是在从DOM中删除<ul>时,另一次是在将其附加到DOM时。 方法1 可能会导致2次(或更多)回流,因为.html将必须删除当前子元素,然后再附加第二组。决定因素将是.html方法是逐个元素顺序附加还是作为一个DOM元素全部附加。但至少它更容易理解。最好的情况下,它会减少从DOM中删除一个元素,从而可能减轻回流的影响。

但是,这两种方法都比以下方法更可取:

var arrayOfElements = ["<li>....</li>", "<li>....</li>", "<li>....</li>"];
$('.list').children().remove();
for (var i = 0; i < arrayOfElements.length; i++) {
    $(arrayOfElements[i]).appendTo('.list');
}

1
链接具有不同的用例,其中在循环中执行多个附加操作。与 OP 所做的不完全相同。 - charlietfl
但这可能是别人告诉他做他正在做的事情时想到的。我猜方法1在这种情况下会更有效率。 - Colin DeClue
@Musa,对于简单的情况来说,这是非常有说服力的。但是如果涉及到非平凡的DOM呢?比如说被插入元素是整个页面的一部分?还有非平凡的CSS规则?重新布局的成本很大程度上取决于被操作的DOM元素的深度以及应用于DOM的样式的复杂性。 - robbmj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接