为什么删除元素比添加元素花费更多时间?

时间:2017-09-11 07:04:15

标签: javascript jquery html performance dom

我有一张包含很多行的表格(如10.000) (注意:我意识到让一张桌子很大没什么意义,但我想了解下面的行为)。
当我收到新数据时,我想先清除行。奇怪的是,清除表格比从头开始构建行需要更长的时间。使用html("")或普通JS innerHTML = ""清除表行需要1.5分钟,远远超过构建行本身,这需要不到一秒钟。

所以我的问题:
- 为什么删除元素比添加元素花费更多时间?幕后发生的事情'? (请注意我的问题是为什么一个,我不是在寻找可能的解决方法)。

更新

我注意到表行和单元格已经应用了浮动定义,当我删除浮动时,表格在实例中被清空。
我还是真的很想理解为什么浮动使得删除行的速度变慢了。
这里有一个小提琴:https://jsfiddle.net/maaikeb/t5pduuue/
在Chrome中,需要25秒才能清空表格,只需23秒 ms 即可将其附加到DOM。

*我阅读了以下帖子,但他们更多地谈论了可能的解决方案,而不是为什么删除元素比添加元素需要更多时间,删除它们时实际发生的事情

jQuery empty is very slow
jQuery empty is very slow
What is the best way to remove a table row with jQuery?
Deleting table rows in javascript
jquery - fastest way to remove all rows from a very large table

5 个答案:

答案 0 :(得分:2)

我假设您在IE上表现不佳。

我之所以这样说是因为$.empty方法在循环中为表中的每个已删除元素调用removeChild,并且该方法在IE中总是有不良表现 - 请参阅{ {3}}进行了一些性能比较和解决方案。

无论你使用大型DOM做什么, 都会在IE上表现不佳。 this article for short case study是社区如何被这个简单事实迷惑的一个例子。 :)

答案 1 :(得分:1)

如果你问为什么清空桌子的时间比连接它要长1000倍,那么它就不应该:这是一个bug。

您可以根据浏览器,版本,jQuery版本或操作系统找到重要的性能差异,但25s vs 23ms太多了。在某个地方你似乎遇到O(N^2)操作。不到那个人打开门票,浏览器的开发者就会认出来。

无论如何,删除元素并不总是比添加元素更快。我们的直觉说 destroy 应该比 create 更快,但在操纵DOM时并不一定如此。 jQuery和浏览器都需要进行额外的工作来获取元素。

如果你看一下jQuery append() function的当前(3.2.1)实现,你会发现它基本上做的是使用本机JS方法appendChild()。另一方面,jQuery empty() functionhtml()使用empty())需要循环遍历所有内部元素,并负责删除每个内部元素的相关数据(例如事件)以防止内存泄漏。

而且,如果您只使用vanilla JS,浏览器在删除元素时仍需要检查大量内容。如果您想进入浏览器的内部,可以查看Firefox issue

如果您选择removeChild()innerHtmltextContent(),浏览器始终需要重新计算样式和布局:检查this one in Chromium

这种错误很常见。如果您在关键字“removeChild”和“slow”的问题中搜索Chromium,那么您会得到一个漂亮的long list。有时它们会因为修复引入回归而来来去去,例如涉及浮动元素的this caseThis other one对您来说可能特别有趣,因为它证明某些错误与您选择删除元素的方法没有关联,因为,就像您的情况一样,它会在复杂的CSS规则应用于该元素时出现(建议比浏览器触发回流)。

我无法在Firefox和Chrome中重现您的问题,因此我无法解决25秒或1.5分钟的确切原因,但它似乎确实存在于更新版本中修复的错误。如果您仍然拥有相同的旧版本并且可以重现它,那么检查以相反顺序(从lastChild开始)删除元素是否有帮助可能是值得的。也许你避免重新计算所有浮动兄弟姐妹的位置。

下次您可能想要打开一张票并按照他们如何找到错误并修复它。它将满足您的好奇心,您可以学习很多关于浏览器内部的知识!

答案 2 :(得分:0)

不是循环整个DOM,而是再次删除和重新渲染,你可以使用hide()和show()。由于检索隐藏列也非常容易,因此速度快且性能良好。请找到有用的snipet。



//did based on checkbox here update to ur requirement hide() callback remains same.

$("input:checkbox:not(:checked)").each(function() {
    var column = "table ." + $(this).attr("name");
    $(column).hide();
});

$("input:checkbox").click(function(){
    var column = "table ." + $(this).attr("name");
    $(column).toggle();
});

td, th {
    padding: 6px;
    border: 1px solid black;
}

th {
    background-color: #f0eae2;
    font-weight: bold;
}

table {
    border: 1px solid black;
}

<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<p><input type="checkbox" name="first_name" checked="checked"> First Name 
  <input type="checkbox" name="last_name"> Last Name 
  <input type="checkbox" name="email" checked="checked"> Email</p>

<table id="report">
<thead>
<tr>
 <th class="first_name">First Name</th>
 <th class="last_name">Last Name</th>
 <th class="email">Email</th>
</tr>
</thead>
<tbody>
<tr>
 <td class="first_name">Larry</td>
 <td class="last_name">Hughes</td>
 <td class="email">larry@gmail.com</td>
</tr>
<tr>
 <td class="first_name">Mike</td>
 <td class="last_name">Tyson</td>
 <td class="email">mike@gmail.com</td>
</tr>
</tbody>
&#13;
&#13;
&#13;

答案 3 :(得分:0)

你可以通过为其内部HTML指定空字符串的值来清除表。然后它不会遍历每个row元素来查找header,tbody或row来删除它.Hence会比你当前的方法更快

$(&#34;#yourtableid&#34)的HTML(&#34;&#34);

答案 4 :(得分:0)

您只是想知道为什么。但是也许其他人想知道加快速度的方法...因此,我只想指出我遇到的情况。

我在快速移除之前动态创建的元素时遇到了问题(这是svg动画的一部分……)。 我的解决方案是将以前创建的元素存储在数组中。稍后为了删除,我只需要遍历数组以删除它们。那快得多了,对我有用。 最后,对于我来说,不是.remove()(或.removeChild())函数本身的性能,而是DOM扫描指定元素的速度(如Davids的回答所述),这使该过程变慢了。