Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does removing elements take more time than adding elements?

Tags:

I have a table with a lot of rows (like 10.000).
(Note: I realize it doesn't make sense to have a table that large, but I'd like to understand the below behavior).
When I receive new data I want to clear the rows first. Weirdly enough, clearing the table takes much longer than building the rows from scratch. Clearing the table rows with html("") or plain JS innerHTML = "" takes 1.5 minutes, much more than building the rows themselves, which takes less than a second.

So my question:
- Why does removing elements take more time than adding them? What happens 'behind the scenes'?
(Please note my question is a Why one, I'm not looking for possible workarounds).

UPDATE:

I noticed that the table row and cells have floating definitions applied to them, and when I remove the float, the table is emptied out in an instance.
I'd still really like to understand why the float makes the removal of the rows so much slower.
Here a fiddle: https://jsfiddle.net/maaikeb/t5pduuue/
In Chrome it takes 25 seconds to empty the table, and only 23 ms to append it to the DOM.

*I read the below posts, but they talk more about possible solutions, and less about why removing elements takes more time than adding them, what actually happens when you remove them

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

like image 863
Kemeia Avatar asked Sep 11 '17 07:09

Kemeia


2 Answers

I'm assuming you have bad performance on IE.

I'd say that's because the $.empty method calls removeChild in a loop for every removed element in the table and that method always had bad performance in IE - see this article for short case study with some performance comparisons and resolutions.

No matter what you do with large DOM you will have bad performance on IE. This article on appendChild in large DOM on IE is an example of how the community is still befuddled by this simple fact. :)

like image 105
sztrzask Avatar answered Nov 19 '22 05:11

sztrzask


If you ask why emptying the table should take 1000 times longer than appending it, well, it just shouldn't: that is a bug.

You can find important performance differences depending on the browser, its version, the version of jQuery or the OS, but 25s vs 23ms is way too much. It seems than somewhere you hit a O(N^2) operation. For less than that people open tickets and the browser's developers acknowledge them.

Anyway, removing elements its not always faster that adding them. Our intuition says that destroy should be faster than create but that's not necessarily true when it comes to manipulate the DOM. Both jQuery and the browser need to make additional work to take elements out.

If you have a look to the current (3.2.1) implementation of jQuery append() function you will see that what it basically does is to use the native JS method appendChild(). On the other hand jQuery empty() function (html() uses empty()) needs to loop over all the inner elements and take care of removing the related data (e.g. events) to each of the inner elements to prevent memory leaks.

And, if you use just vanilla JS, the browser still needs to check a big bunch of things when removing elements. If you want to get into the browser's internals you can check this Firefox issue.

It doesn't matter if you go for removeChild(), innerHtml or textContent(), the browser always need to recalculate styles and layout: check this one in Chromium.

This kind of bugs are common. If you search into the Chromium for issues with the keywords "removeChild" and "slow" you get a pretty long list. Sometimes they come and go due to fixes introducing regressions, like in this case involving floating elements. This other one can be specially interesting for you, because it proofs that some bugs are not connected with the method you choose to remove the elements and because, like in your case, it shows up when complex CSS rules are applied to that elements (suggesting than the browser triggered a reflow).

I was unable to reproduce your issue neither in Firefox nor in Chrome, so I can't address the exact reason for the 25 seconds or 1.5 minutes, but it really seems to a bug fixed in more recent versions. If you still have the same old version and can reproduce it, it could be worth to check if removing the elements in inverse order (starting from lastChild) helps. Perhaps you avoid recalculating the position of all the floating siblings after the one you remove.

Next time maybe you want to open a ticket and follow how they find the bug and fix it. It will satisfy your curiosity and you can learn a lot about browser internals!

like image 20
David Avatar answered Nov 19 '22 05:11

David