簡體   English   中英

為什么刪除元素比添加元素花費更多的時間?

[英]Why does removing elements take more time than adding elements?

我有一個有很多行的表(比如 10.000)。
(注意:我意識到擁有這么大的桌子是沒有意義的,但我想了解以下行為)。
當我收到新數據時,我想先清除行。 奇怪的是,清除表比從頭開始構建行花費的時間要長得多。 使用html("")或純 JS innerHTML = ""清除表格行需要 1.5 分鍾,比構建行本身要多得多,后者只需要不到一秒鍾。

所以我的問題:
- 為什么刪除元素比添加元素花費更多的時間? “幕后”發生了什么?
(請注意我的問題是一個為什么,我不是在尋找可能的解決方法)。

更新

我注意到表格行和單元格應用了浮動定義,當我刪除浮動時,表格在一個實例中被清空。
我仍然很想了解為什么浮動會使行的刪除速度如此之慢。
這里有一個小提琴: https : //jsfiddle.net/maaikeb/t5pduuue/
在 Chrome 中,清空表需要 25 秒,而將它附加到 DOM 只需要 23毫秒

*我閱讀了以下帖子,但他們更多地討論了可能的解決方案,而不是談論為什么刪除元素比添加元素花費更多時間,刪除它們時實際會發生什么

jQuery 空很慢
jQuery 空很慢
使用 jQuery 刪除表格行的最佳方法是什么?
在javascript中刪除表格行
jquery - 從非常大的表中刪除所有行的最快方法

我假設您在 IE 上的表現不佳。

我會說這是因為$.empty方法在循環中為表中的每個已刪除元素調用removeChild並且該方法在 IE 中的性能總是很差 - 請參閱本文以了解一些性能比較和解決方案的簡短案例研究

無論您對大型 DOM 做什么,您在 IE 上的性能都會很差。 這篇關於 IE 上大型 DOM 中的 appendChild 的文章就是一個例子,說明社區仍然被這個簡單的事實所迷惑。 :)

如果你問為什么清空表比追加它需要 1000 倍的時間,好吧,它不應該:這是一個錯誤。

您可以根據瀏覽器、其版本、jQuery 版本或操作系統找到重要的性能差異,但 25 秒與 23 毫秒太多了。 似乎您在某個地方遇到了O(N^2)操作。 比這還少,人們打開票證,瀏覽器的開發人員承認他們。

無論如何,刪除元素並不總是比添加它們更快。 我們的直覺是, destroy應該比create快,但在操作 DOM 時不一定如此。 jQuery 和瀏覽器都需要做額外的工作來取出元素。

如果您查看jQuery append()函數的當前(3.2.1)實現,您會發現它的主要作用是使用原生 JS 方法appendChild() 另一方面, jQuery empty()函數html()使用empty() )需要遍歷所有內部元素,並注意刪除每個內部元素的相關數據(例如事件)以防止內存泄漏。

而且,如果你只使用 vanilla JS,瀏覽器在刪除元素時仍然需要檢查一大堆東西。 如果你想進入瀏覽器的內部,你可以檢查這個Firefox 問題

無論你選擇removeChild()innerHtml還是textContent() ,瀏覽器總是需要重新計算樣式和布局:在 Chromium 中檢查這個

這種bug很常見。 如果您在 Chromium 中搜索有關關鍵字“removeChild”和“slow”的問題,您會得到一個很長的列表 有時它們會因為引入回歸的修復而來來去去,就像在這種情況下涉及浮動元素。另一個對您來說可能特別有趣,因為它證明某些錯誤與您選擇的刪除元素的方法無關,並且因為,就像在您的情況下一樣,當復雜的 CSS 規則應用於該元素時(建議比瀏覽器觸發回流)。

我無法在 Firefox 和 Chrome 中重現您的問題,因此我無法解決 25 秒或 1.5 分鍾的確切原因,但這似乎確實是更新版本中修復的錯誤。 如果您仍然擁有相同的舊版本並且可以重現它,那么檢查以相反的順序(從lastChild開始)刪除元素是否有幫助可能是值得的。 也許您避免在刪除后重新計算所有浮動兄弟姐妹的位置。

下次也許你想打開一張票,並按照他們如何找到錯誤並修復它。 它會滿足你的好奇心,你可以學到很多關於瀏覽器內部的知識!

您可以使用 hide() 和 show() 代替循環整個 DOM 刪除並重新渲染。 由於檢索隱藏列也很容易,因此速度快且性能好。 請發現 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>

您可以通過為其內部 HTML 分配空字符串的值來清除表格。然后它不會遍歷每個行元素來查找標題、tbody 或行來刪除它。因此會比您當前的方法更快。

$("#yourtableid").html("");

你只是想知道為什么。 但也許其他人想知道一種加快速度的方法......因此我只想指出我遇到的情況。

我在刪除之前動態創建的元素時遇到了問題(是 svg 動畫的一部分......有點)。 我的解決方案是將之前創建的元素存儲在數組中。 后來為了刪除,我只需要遍歷數組來刪除它們。 那要快得多,而且對我有用。 最后,對於我的情況,不是 .remove()(或 .removeChild())函數本身的性能,而是對指定元素的 DOM 掃描(如 Davids 的回答中所述)減慢了進程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM