DOM DocumentFragments

I was playing around with DOM DocumentFragments recently, in JavaScript, seeing what I could make with them. Roughly speaking, a DocumentFragment is a lightweight container that can hold DOM nodes. It’s part of the DOM 1 specification and is supported in all modern browsers (it was added to Internet Explorer in version 6).

In reading up on them I came across an interesting point, from the specification:

Furthermore, various operations — such as inserting nodes as children of another Node — may take DocumentFragment objects as arguments; this results in all the child nodes of the DocumentFragment being moved to the child list of this node.

This means that if you take a bunch of DOM nodes and append them to a fragment then you can simply append the fragment to the document, instead (and achieve the same result – as if you had appended each node individually). I instantly smelled a possible performance improvement here. I investigated a little bit further and noticed that DocumentFragments support the cloneNode method, as well. This provides all the functionality that you need to highly-optimize your DOM insertion code.

I set up a simple demo to test the theory.

Let’s take the situation where you have a bunch of DOM nodes that you need to append into the document (in the demo it’s 12 nodes – 8 at the top level – against a whole mess of divs).

var elems = [
	document.createElement("hr"),
	text( document.createElement("b"), "Links:" ),
	document.createTextNode(" "),
	text( document.createElement("a"), "Link A" ),
	document.createTextNode(" | "),
	text( document.createElement("a"), "Link B" ),
	document.createTextNode(" | "),
	text( document.createElement("a"), "Link C" )
];

function text(node, txt){
	node.appendChild( document.createTextNode(txt) );
	return node;
}

Normal Append

If we wanted to append these nodes into the document we would probably do it in this traditional manner: Looping through the nodes and cloning them individually (so that we can continue to append them all throughout the document).

var div = document.getElementsByTagName(“div”);

for ( var i = 0; i < div.length; i++ ) { for ( var e = 0; e < elems.length; e++ ) { div[i].appendChild( elems[e].cloneNode(true) ); } }[/js] DocumentFragment Append

However, when we bring DocumentFragments into the picture we can immediately see a different structure. To start we append all our nodes into the fragment itself (built using the createDocumentFragment method).

But the interesting point comes when it’s time to actually insert the nodes into the document: We only have to call appendChild and cloneNode once for all the nodes!

var div = document.getElementsByTagName(“div”);

var fragment = document.createDocumentFragment();
for ( var e = 0; e < elems.length; e++ ) { fragment.appendChild( elems[e] ); } for ( var i = 0; i < div.length; i++ ) { div[i].appendChild( fragment.cloneNode(true) ); }[/js] Setting some time stamps we can see our results pay off in spades:

Browser Normal (ms) Fragment (ms)
Firefox 3.0.1 90 47
Safari 3.1.2 156 44
Opera 9.51 208 95
IE 6 401 140
IE 7 230 61
IE 8b1 120 40

As it turns out: A method that is largely ignored in modern web development can provide some serious (2-3x) performance improvements to your DOM manipulation.

Posted: July 21st, 2008


Subscribe for email updates

52 Comments (Show Comments)



Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question concerning the content of this post, please feel free to contact me.


Secrets of the JavaScript Ninja

Secrets of the JS Ninja

Secret techniques of top JavaScript programmers. Published by Manning.

John Resig Twitter Updates

@jeresig / Mastodon

Infrequent, short, updates and links.