views:

1294

answers:

3

Let me start off by apologizing for not giving a code snippet. The project I'm working on is proprietary and I'm afraid I can't show exactly what I'm working on. However, I'll do my best to be descriptive.

Here's a breakdown of what goes on in my application:

  1. User clicks a button
  2. Server retrieves a list of images in the form of a data-table
  3. Each row in the table contains 8 data-cells that in turn each contain one hyperlink
    • Each request by the user can contain up to 50 rows (I can change this number if need be)
    • That means the table contains upwards of 800 individual DOM elements
    • My analysis shows that jQuery("#dataTable").empty() and jQuery("#dataTable).replaceWith(tableCloneObject) take up 97% of my overall processing time and take on average 4 - 6 seconds to complete.

I'm looking for a way to speed up either of the above mentioned jQuery functions when dealing with massive DOM elements that need to be removed / replaced. I hope my explanation helps.

A: 

Do you have to repopulate all at once, or can you do it by chunks on a setTimeout()? I realize it'll probably take even longer in chunks, but it's worth a lot for the user to see something happening rather than an apparent lockup.

Nosredna
It has to be done all at once.
Levi Hackwith
A: 

I recently had very large data-tables that would eat up 15 seconds to a minute of processing when making changes due to all the DOM manipulation being performed. I got it down to <1 second in all browsers but IE (it takes 5-10 seconds in IE8).

The largest speed gain I found was to remove the parent element I was working with from the DOM, performing my changes to it, then reinserting it back into the DOM (in my case the tbody).

Here you can see the two relevant lines of code which gave me huge performance increases (using Mootools, but can be ported to jQuery).

update_table : function(rows) {
 var self = this;
 this.body = this.body.dispose();  //<------REMOVED HERE
 rows.each(function(row) {
  var active = row.retrieve('active');
  self.options.data_classes.each(function(hide, name) {
   if (row.retrieve(name) == true && hide == true) {
    active = false;
   }
  });
  row.setStyle('display', (active ? '' : 'none'));
  row.store('active', active);
  row.inject(self.body);   //<--------CHANGES TO TBODY DONE HERE
 })
 this.body.inject(this.table);  //<-----RE-INSERTED HERE
 this.rows = rows;
 this.zebra();
 this.cells = this._update_cells();
 this.fireEvent('update');
},
tj111
Okay, I can see the logic in this. However, in my case, I'm basically removing a table from within a <td>. You'd think that wouldn't take long, but the table inside the <td> is what has over 800 elements. Given this scenario, do you think your proposed solution would still work?
Levi Hackwith
I do. They are introducing DOM Fragments in HTML 5 to deal with this very problem. I think if you try pulling the <td>, updating it, and putting it back in you'll see huge performance gains. Also it's very simple to do, I made the change with 2 lines of code. If you have Firebug installed you can use the 'Profile' button under the 'Console' tab to see where your performance is getting eating as well.
tj111
+3  A: 

jQuery empty() is taking a long time on your table because it does a truly monumental amount of work with the contents of the emptied element in the interest of preventing memory leaks. If you can live with that risk, you can skip the logic involved and just do the part that gets rid of the table contents like so:

    while ( table.firstChild )
        table.removeChild( table.firstChild );

or

    table.children().remove();
chaos
This worked. I'll be doing more work regarding the possible memory leaks but this totally sped things up. Thank you everyone!
Levi Hackwith