7

Without getting into too many details, I'm cleaning up whitespace inside tables using javascript. I need to remove large amounts of textnodes. This seems to be the bottleneck in my script when it comes to IE9.

All of the following methods do the job, but they cause a tremendous slow-down.

domNode.removeNode(true);
domNode.nodeValue = "";
domNode.parentNode.removeChild(domNode);

Is there a way to do a bulk remove or a way to hide them in the dom or such. Just something faster.

I've also tried this on the textnodes:

domNode.innerHTML = '';

While it executes quickly, the textnodes seem to be unphased by it.

Also, I need to retain the event bindings so a .innerHTML replace on the whole table doesn't really seem like an option. Though it does run about 5 times faster.

Update: Rough benchmarks on suggested solutions:

//around 480ms
stripWhitespaceTextNodes(domNode);

//around 640ms
parent.removeChild(domNode);
stripWhitespaceTextNodes(domNode);
parent.insertBefore(domNode, nextNode);

//around 700ms
tables[i].style.visibility = 'hidden';
stripWhitespaceTextNodes(domNode);
tables[i].style.visibility = 'visible';

//around 1140ms
tables[i].style.display = 'none';
stripWhitespaceTextNodes(domNode);
tables[i].style.display = 'block';

This was done on 4 tables with one table having 1500 rows.

The crux of the stripWhitespaceTextNodes() function is removing text nodes, this seems to be the bottleneck and here are my various attempts at it.

domNode.parentNode.removeChild(domNode);
domNode.removeNode(true);
domNode.nodeValue = ""; // <-- CURRENTLY THIS ONE IS THE TOP RUNNER
domNode.replaceWholeText('');
domNode.deleteData(0, domNode.length);

var txtNode = document.createTextNode("");
domNode.parentNode.replaceChild(txtNode, domNode);
parent.insertBefore(domNode, nextNode);

//fast but doesn't work
domNode.innerHTML = '';
Serhiy
  • 2,505
  • 3
  • 33
  • 49
  • I would be interested in the details. Why do you need to remove whitespace-textNodes from a table, they won't affect displaying? – Bergi Jun 06 '12 at 08:35
  • They do in IE9. Refer to this question for those details. http://stackoverflow.com/questions/9895095/wanted-ie9-table-cell-ghost-alive-and-without-js As far as why can't I fix it on the server-side, that's another long story... – Serhiy Jun 06 '12 at 08:46
  • Have you tried to use domNode.innerText = '' or domNode.textContent = '' to remove the textnodes? – xcopy Jun 11 '12 at 16:31
  • Still struggeling with this one? I gotta say you're persistent to make it work. – jornare Jun 14 '12 at 09:08
  • Keep in mind that option B `[...].nodeValue = "";` does not actually remove the node. That's why it's quicker. –  Jun 14 '12 at 20:23
  • @vsync you lose event bindings that way – Serhiy Mar 10 '16 at 00:54

3 Answers3

6

The usual trick for this is to remove the container on which you're performing these operations from the DOM before doing the big changes, and then put it back when you're done.

So in your case, that might be:

var table = /* ...get a reference to the table...*/;
var nextNode = table.nextSibling; // May be null, that's fine
var parent = table.parentNode;
parent.removeChild(table);
/* ...clean up the text nodes... */
parent.insertBefore(table, nextNode);

Event handlers remain attached even when the tree is detached from the page's DOM, so they'll be there when the tree is put back.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • If you just want to prevent repaints, `table.style.display="none"` should be enough. – Bergi Jun 06 '12 at 08:37
  • @Bergi: Not so much re *paints* as re *flows*. But yes, absolutely, the OP should try just making the table non-displayable as well as the above, and pick the one that works best for him/her. – T.J. Crowder Jun 06 '12 at 08:39
  • Where's the difference? Surely, there might be reflows without repaints when js calculates with css values -not here-, but neither of them should happen to hidden elements. – Bergi Jun 06 '12 at 08:43
  • I may have jumped the gun on the DOM redraw assumption. Setting display none on the table just doubled the execute time for some reason...? – Serhiy Jun 06 '12 at 08:44
  • @Serhiy: What about the detaching suggested in the answer? – T.J. Crowder Jun 06 '12 at 09:14
  • Thank you for the help, though that added about 100ms+. Though that is less than most of my other attempts at speeding this up :) Thanks anyways, some updates up-top. – Serhiy Jun 06 '12 at 10:10
0

One way you can do it is to clone the entire table and do manipulations "off-site". It means doing the operations to the clone where the clone is not on the DOM. Afterwards, do a single replace of the entire table with the modified clone. That way, the operations won't be bogged down.

Here's an answer that refers to several methods of "cloning" the DOM and creating "container elements" for operations outside the DOM.

Community
  • 1
  • 1
Joseph
  • 117,725
  • 30
  • 181
  • 234
  • I may have jumped the gun on the DOM redraw assumption. Creating a cloned domNode and working with that does not appear any faster. It seems like maybe IE's domNode manipulation tools may be just that slow. – Serhiy Jun 06 '12 at 08:48
0

You can try detaching your table (table DOM element) from the document, walk over it and remove white space text nodes as you do, and then insert the table back at the original position. In theoretically you should gain speed - Render Tree would not need to be updated on each pass, which is costly for tables in documents.

Sergey Ilinsky
  • 31,255
  • 9
  • 54
  • 56
  • Thanks for the suggestion, thats what I was thinking/hoping for. However when I ran tests, working on tables removed out of the DOM actually went slower. It makes no sense, but that's the result I got. – Serhiy Jun 07 '12 at 14:00