Does using a document fragment really improve performance?
I've got a doubt regarding performance in JS.
Say, I've got the next code:
var divContainer = document.createElement("div"); divContainer.id="container";
var divHeader = document.createElement("div"); divHeader.id="header";
var divData = document.createElement("div"); divData.id="data";
var divFooter = document.createElement("div"); divFooter.id="footer";
divContainer.appendChild( divHeader );
divContainer.appendChild( divData );
divContainer.appendChild( divFooter );
document.getElementById("someElement").appendChild( divContainer );
This code just creates the shell for some other functions to create a grid, the process to create the grid is very complex and with many validations and currently I'm using 2 methods to fill the grid, one creating the whole html in an array variable and the other one creating elements and appending them to a documentFragment
.
My question is if there's really an improvement regarding performance when using fragments, as I understand them - they manage elements on memory, so they're not attached to the document, thus, not triggering DOM recalculation and other nasty stuff. But the way I'm creating my variables, they're not attached to any DOM Element until i append the container to the actual page.
So I was wondering if the previous code has better performance than using a document fragment that wraps it all like so:
var fragment = document.createDocumentFragment();
var divContainer = document.createElement("div"); divContainer.id="container";
var divHeader = document.createElement("div"); divHeader.id="header";
var divData = document.createElement("div"); divData.id="data";
var divFooter = document.createElement("div"); divFooter.id="footer";
divContainer.appendChild( divHeader );
divContainer.appendChild( divData );
divContainer.appendChild( divFooter );
fragment.appendChild( divContainer )
document.getElementById("someElement").appendChild( fragment.cloneNode(true) );
As I've already said, this is a question regarding performance, I know that as a best practice it's recommended to use fragments, but I can't take the thought out of my head that doing that just creates a new object in memory and does nothing, so I assume that ditching the fragment in this case is valid.
Hopefully some js guru / god will shine a light of hope in here and help us with this issue.
Edit: So, I've been looking around for stuff related to this issue and it seems that documentFragments doesn't necessarily means better performance.
It's just an "in memory" container of nodes. The difference between a fragment and say, a <div>
is that the fragment has no parent and it will never be on the DOM, just in memory, which means that the operations made on the fragment are faster since there's no manipulation of the DOM.
W3C's documentation on documentFragments is very vague but to the point and also, everybody's favorite browser does not uses real fragments, instead it creates a new document according to this MSDN documentation. Which means, fragments on IE are slower.
So, the question prevails, if I create an element (a <div>
for example) in a variable but DO NOT APPEND IT TO THE DOM, add elements (divs, tables, etc ) and stuff and after all the work has been done (loops, validations, styling of elements), that element is appended, is it the same as a fragment?
Given the fact that IE uses a "fake" fragment I'd say at least in IE using that approach (using an element such as a div, not a fragment) is better, I really don't care for IE but I need to test it ( office's policy ).
Also, if I create all the html on an array like so:
var arrHTML = ["<table>","<tr>", ....];
and then do this
document.getElementById("someElement").innerHTML = arrHTML.join("");
It's way faster on IE, but other major browsers ( FF, Chrome, Safari and Opera ) perform better when using a container and then appending it (fragment or div).
All of this is because the process to create all the elements is done really fast, around 8 - 10 seconds to create up to 20,000 rows with 24 columns, it's a lot of elements / tags, but the browser seems to freeze a few seconds when they're all appended at once, if I try and append them one by one, it's hell.
Thanks again folks, this is really interesting and fun.
Solution 1:
Document Fragment is much faster when it is used to insert a set of elements in multiple places. Most answers here point out its un-utility, but this is to demonstrate its strength.
Lets take an example.
Say we need to append 20 divs in 10 elements with class container.
Without:
var elements = [];
for(var i=20; i--;) elements.push(document.createElement("div"));
var e = document.getElementsByClassName("container");
for(var i=e.length; i--;) {
for(var j=20; j--;) e[i].appendChild(elements[j].cloneNode(true));
}
With:
var frag = document.createDocumentFragment();
for(var i=20; i--;) frag.appendChild(document.createElement("div"));
var e = document.getElementsByClassName("container");
for(var i=e.length; i--;) e[i].appendChild(frag.cloneNode(true));
For me using a document fragment turns out to be 16 times faster on Chrome 48.
Test on JsPerf
Solution 2:
Normally you'd want to use a fragment to avoid reflows (repainting the page). A good case would be if you were looping over something and appending within the loop, however, I think modern browsers optimize for this already.
I set up a jsPerf to illustrate a good example of when to use a fragment here. You'll notice in Chrome that there is hardly a difference (modern optimization at work, I presume), however, in IE7 I get .08 ops/sec without the fragment, 3.28 ops/sec with a fragment.
So, if you're looping over a large data set and appending A LOT of elements use a fragment instead so you only have one reflow. If you're only appending to the dom a few times or you're only targetting modern browsers it isn't necessary.
Solution 3:
I've written a jspref to test this and it appears the node fragment is 2.34 % faster
http://jsperf.com/document-fragment-test-peluchetti