首页 \ 问答 \ 为什么分离和追加比直接更改html更有效?(Why is detaching and appending more efficient than changing html directly?)

为什么分离和追加比直接更改html更有效?(Why is detaching and appending more efficient than changing html directly?)

有人告诉我,当在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");

为什么appraoch 2更有效率,有多重要?


I was told that when inserting multiple elements into the DOM, it is more efficient to first detach the destination element, insert the elements, and then append it back to the DOM. I would like to know why.

For instance,

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");

Why is appraoch 2 more efficient, and by how much significance?


原文:https://stackoverflow.com/questions/26767804
更新时间:2019-11-21 10:10

最满意答案

向DOM添加一系列元素时,每个元素都会触发浏览器重排页面。 将一个元素添加到已经准备好而不在DOM上的页面上,然后将其附加到DOM只会导致页面的一次重排。

来自: http//www-archive.mozilla.org/newlayout/doc/reflow.html

所有回流都有一个原因,它在回流状态对象中保持(并且可能变异,如下所述)。 回流原因控制框架在回流期间的反应方式,并且是以下之一:

文章接着列出了回流的原因,以下是其中一个原因:

增量,当帧树中的某些东西改变时; 例如,当从网络读取更多内容时,或某些脚本操纵DOM。 增量回流针对帧层次结构中的单个帧。 在增量回流期间,帧可以假设from above'' (for example, available width) have changed; instead, something计算的约束from above'' (for example, available width) have changed; instead, something from above'' (for example, available width) have changed; instead, something “框架内的from above'' (for example, available width) have changed; instead, something已经改变,这可能会对框架层次结构产生自下而上的影响。

至于性能改进,我会把它留给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次回流。 一旦<ul> DOM <ul>从DOM中删除,一次将其附加到DOM。 Approach 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');
}

When appending a series of elements to the DOM each triggers the browser to reflow the page. Adding one element to the page that has already been prepared while not on the DOM then appending that to the DOM only causes one reflow of the page.

From: http://www-archive.mozilla.org/newlayout/doc/reflow.html

All reflows have a reason, which is maintained in the reflow state object (and may mutate, as described below). The reflow reason controls how a frame reacts during a reflow, and is one of the following:

The article goes on to list the reasons for a reflow, the following is one such reason:

Incremental, when something in the frame tree changes; for example, when more content is read from the network, or some script manipulates the DOM. An incremental reflow is targeted at a single frame in the frame hierarchy. During an incremental reflow, a frame can assume that none of the constraints computed from above'' (for example, available width) have changed; instead, somethingwithin'' the frame has changed, which may have bottom-up impact to the frame hierarchy.

As for performance improvements I will leave that to 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

Source: http://ejohn.org/blog/dom-documentfragments/

Your examples are somewhat flawed though.

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

Should be written as:

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

Secondly

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

Between the two examples this one MAY actually be better. Why?

Because:

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

Can cause up to (and probably will) 2 reflows. Once when the <ul> is removed from the DOM and once when it is appended to the DOM. Approach 1 may cause 2 (or more) reflows, as .html will have to remove the current children and then append the second set. The determining factor will be if the .html method appends each element sequentially or all at once as one DOM element. But at very least it is easier to grok. And at best it removes one less element from the DOM potentially diminishing the effects of the reflow.

However both methods are preferable to the following:

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

相关文章

更多

最新问答

更多
  • jsPlumb draggable element javascript函数(jsPlumb draggable element javascript function)
  • MVC4:ViewModel(带有radiobuttonlist)在HttpPost之后为空(MVC4: ViewModel (with radiobuttonlist) is empty after HttpPost)
  • 如何在同一帐户上设置“Dev repo”(在prod和团队之间)(How to set up a “Dev repo” (between the prod and the team) on the same account)
  • 如何在tcl中将eth0配置为发送方udp端口(how to configure eth0 as a sender udp port in tcl)
  • 如何在datarow []中的列中找到最大值?(How to find max value in a column in a datarow[] ?)
  • 如何使用预定义文本替换来自数据库的部分结果(How do I replace part of result coming from Database with predefined text)
  • Selenium Java注入了新的Javascript函数(Selenium Java inject new Javascript function)
  • 使用.on的多个下拉菜单选择文本仅适用于第一个下拉列表(Multiple Dropdowns Menu Selection text using .on works only on first dropdown)
  • 快速将黄土曲线添加到大型数据集图中的方法(Quick way to add loess curve to large data set graph)
  • FilteringSelect in mvc(FilteringSelect in mvc)
  • 在Delphi XE2中开发Mac或iOS应用程序需要哪些硬件/软件?(What hardware/software is necessary to develop Mac or iOS apps in Delphi XE2?)
  • 在原型的构造函数中初始化属性时获取“未定义”(Getting 'undefined' when a property is initialized in the constructor of a prototype)
  • 通过越狱加载的应用程序的Documents文件夹位置(Location of Documents folder for an app loaded via jailbreak)
  • 在OpenGL中使用可编程和固定管道功能(Using both programmable and fixed pipeline functionality in OpenGL)
  • 将任何用户输入重定向到单独的底层程序(redirect any user input to a separate underlying program)
  • 编辑文本不能正常工作android(Edit texts not working properly android)
  • “user_denied”Facebook应用页面上的Facebook用户区域设置(Facebook user locale on “user_denied” facebook app page)
  • 在大图像中找到小的部分透明图像的坐标(find coordinates of small partially-transparent image within a large image)
  • 我如何在cakephp 3.1中获得完整的相对路径?(How i can get full relative path of image in cakephp 3.1?)
  • 如何保存拖动标记的新本地化?(How to save new localization of dragged marker?)
  • MySQL UPDATE vs INSERT和DELETE(MySQL UPDATE vs INSERT and DELETE)
  • 在执行查询之前,在SQLAlchemy模型中将datetime转换为unix时间戳?(Convert datetime to unix timestamp in SQLAlchemy model before executing query?)
  • OpenCL与OpenGL互操作的优势(Advantage of OpenCL interoperability with OpenGL)
  • 如何解析用点和等分隔的数据然后添加到listview(How to parsing data from delimited with dot and equal then add to listview)
  • 带调试输出的X3解析器段错误(BOOST_SPIRIT_X3_DEBUG)(X3 parser segfaults with debug output (BOOST_SPIRIT_X3_DEBUG))
  • 将文件夹名称添加到fgrep结果(Add folder name to fgrep result)
  • 在MySQL中加载一个表是非常慢的(Loading one table in MySQL is ridiculously slow)
  • 如何将JSON放入PHP变量?(How do I put JSON into a PHP Variable?)
  • 如何绕过Microsoft.Speech.Recognition中的不流畅?(How to bypass disfluencies in Microsoft.Speech.Recognition?)
  • 原点的最后一行是什么?(What is the last row of an origin for?)