Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient Javascript for DOM modifications

Say, I've got an HTML file that I want to process using Javascript. For example:

  • Add some DOM elements, like span or div wrappers.
  • Change the document styling a bit, like base font size, line-height, etc.
  • Use a hyphentor to add ­ entities.

What would be the most efficient way to do this, i.e. I'd like to do it with a minimum amount of reflows.

The ideal case would be having the JS-code run before even the first layout. Is this possible? I know, it's generally a bad idea to execute expensive scripts before the page has been displayed for this would make the page look blank for some time and it's a really bad experience. However, I'm going to need this to work offline and this would not be an issue for my project.

Or, is there's a way to do all the dom modifications in one bunch, i.e. a reflow to be triggered after all the alterations have finished?

like image 740
Albus Dumbledore Avatar asked Jul 07 '12 10:07

Albus Dumbledore


2 Answers

There are several ways. The primary goal with all of them is that you end up causing a single - or at least as few as possible - reflows/repaints.

Off-DOM element

You can work with elements without appending to the DOM, and then just append everything together once everything's set up.

The only issue with this is if your code needs to reference offset dimensions, since elements not yet in the DOM do not have any.

var container = document.createElement('section'); //not in the DOM yet
//do some extensive work here to prepare the doc
document.body.appendChild(container); //now we go to the DOM, causing a single re-paint

Doc fragment

A more formalised, and possible improved, variation on this theme would be document fragments, which bring a performance benefit (apparently). They're effectively a second, separate DOM that has no display.

String

Probably the quickest of all of these would be to build up your document as a string. The obvious implication is you can't use DOM methods on it, but if you're happy string-handling and REGEX'ing (not ideal on HTML, of course), could be worth considering.

Finally, if speed is of the essence and you have a LOT of computation or string-handling to do, you might want to harness web workers. These can't talk to the DOM directly, but you can outsource tasks to them and, crucially, they work asynchronously on a separate thread.

like image 185
Mitya Avatar answered Oct 01 '22 05:10

Mitya


Remove the documentElement from the document, modify it and add it back to the document.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <title>...</title>           
    </head>
    <body>
        <script type='text/javascript'>
var docElem = document.documentElement,
    parentNode = docElem.parentNode,
    nextSibling = docElem.nextSibling;
parentNode.removeChild(docElem); // reflow
// ...
docElem.lastChild.appendChild(docElem.ownerDocument.createElement('hr'));
// ...
parentNode.insertBefore(docElem, nextSibling); // reflow
        </script>
    </body>
</html>

This triggers two reflows and zero to two extra repaints.

jsFiddle

like image 24
Saxoier Avatar answered Oct 01 '22 06:10

Saxoier