我有一个有很多行的表(比如10.000行)。
(注意:我知道拥有这么大的表是没有意义的,但我想了解一下下面的行为)。
当我收到新数据时,我想先清除行。奇怪的是,清空表格所需的时间比从头构建行要长得多。使用html("")
或普通的JS innerHTML = ""
清除表行需要1.5分钟,比构建行本身需要不到一秒的时间要多得多。
所以我的问题是:
(请注意,我的问题是为什么是 one,我不是在寻找可能的解决方法)。
更新
我注意到表行和单元格应用了浮动定义,当我删除浮动时,表在一个实例中被清空。
我仍然很想理解为什么使得删除行的速度变得如此之慢。
这里有一把小提琴:https://jsfiddle.net/maaikeb/t5pduuue/
在Chrome中,清空表格需要25秒,将其附加到DOM只需要23 ms。
*我读了下面的帖子,但它们更多地讨论了可能的解决方案,而较少讨论为什么删除元素比添加它们需要更多的时间,当您删除它们时实际发生了什么
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
发布于 2017-09-30 17:12:15
如果你问为什么清空表比追加表多花1000倍的时间,那么,答案是不应该的:这是一个bug。
你可以发现重要的性能差异取决于浏览器,它的版本,jQuery的版本或操作系统,但25s对23ms太多了。它看起来比你遇到O(N^2)
操作的地方要好。低于这个价格,人们就会开票,浏览器的开发者也会承认他们的存在。
无论如何,删除元素并不总是比添加元素更快。我们的直觉告诉我们,销毁应该比创建更快,但当涉及到操作DOM时,这不一定是正确的。jQuery和浏览器都需要做额外的工作来取出元素。
如果您查看一下当前(3.2.1)的jQuery append()
function实现,您会发现它基本上所做的就是使用原生JS方法appendChild()
。另一方面,jQuery empty()
function (html()
使用empty()
)需要遍历所有内部元素,并注意移除每个内部元素的相关数据(例如事件),以防止内存泄漏。
而且,如果你只使用普通的JS,浏览器在删除元素时仍然需要检查一大堆东西。如果你想了解浏览器的内部结构,你可以查看这个Firefox issue。
不管你用的是removeChild()
、innerHtml
还是textContent()
,浏览器总是需要重新计算样式和布局:检查this one in Chromium。
这种bug是很常见的。如果你在Chromium中搜索关键字"removeChild“和"slow”来查找问题,你会得到一个漂亮的long list。有时,它们由于引入回归的修复而来来去去,就像在涉及浮动元素的this case中一样。This other one对你来说可能特别有趣,因为它证明了一些bug与你选择的删除元素的方法无关,而且就像你的例子一样,当复杂的CSS规则应用于这些元素时,它就会出现(建议浏览器触发回流)。
我无法在Firefox和Chrome中重现你的问题,所以我无法解决25秒或1.5分钟的确切原因,但它似乎真的是在最近的版本中修复了一个错误。如果您仍然拥有相同的旧版本并可以重现它,那么检查一下以相反的顺序删除元素(从lastChild
开始)是否有帮助。也许您会避免在移除后重新计算所有浮动同级的位置。
下一次,也许你想打开一张罚单,看看他们是如何找到错误并修复它的。它会满足你的好奇心,并且你可以学到很多关于浏览器内部的知识!
发布于 2017-09-14 17:16:45
我假设你在IE上的表现很差。
我要说这是因为$.empty
方法在一个循环中为表中每个删除的元素调用removeChild
,而该方法在IE中的性能总是很差-参见this article for short case study的一些性能比较和解决方案。
无论你用大的DOM做什么,你的在IE上都会有很差的性能。This article on appendChild in large DOM on IE就是一个例子,说明社区仍然对这个简单的事实感到困惑。:)
发布于 2017-09-18 21:12:28
您可以使用hide()和show(),而不是遍历整个DOM、移除并重新呈现。这是因为检索隐藏列也非常容易,所以速度快且性能好。请找到有用的代码片段。
//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>
https://stackoverflow.com/questions/46149924
复制相似问题