o9ws2g
Last Updated: October 30, 2018
·
49.96K
· thomaslindstr_m

Why you should always append DOM elements using DocumentFragments

If you ever find yourself appending a series of elements to the DOM, you should always use a DocumentFragment to do just that.

A DocumentFragment is a minimal document object that has no parent. It is used as a light-weight version of document to store well-formed or potentially non-well-formed fragments of XML.
https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment

Why? Not only is using DocumentFragments to append about 2700 times faster than appending with innerHTML, but it also keeps the recalculation, painting and layout to a minimum.

TL;DR: Use DocumentFragments. http://jsperf.com/document-fragment-vs-innerhtml-vs-looped-appendchild

When normally we would do this to append elements:

var i = 0; while (i < 200) {
    div.innerHTML += '<li>My list item #' + i + '</li>';
i++; }

doing this would be much faster (although not optimal):

var i = 0; while (i < 200) {
    var el = document.createElement('li');
    el.innerText = 'This is my list item number ' + i;
    div.appendChild(el);
i++; }

However, this solution suffers from recalculation of styles, painting and layout - a lot of it - something you should be very wary about when building performant web apps.

Read more about recalculation of styles, painting and layout here: http://stackoverflow.com/questions/11623299/what-does-recalculate-layout-paint-mean-in-chrome-developer-tool-timeline-record

Wouldn't it be great if there was some way to bypass recalculating, painting and layout for every single element we added, and rather have it just happen once? There is!

var el;
var i = 0;
var fragment = document.createDocumentFragment();

while (i < 200) {
    el = document.createElement('li');
    el.innerText = 'This is my list item number ' + i;
    fragment.appendChild(el);
i++; }

div.appendChild(fragment);

Instead of appending the elements directly to the document when they are created, append them to the DocumentFragment instead, and finish by adding that to the DOM.

Now there's only one (big) DOM change happening, and because of that we're also keeping the recalculation, painting and layout to an absolute minimum.

10 Responses
Add your response

6681

Did not know this, will check it out. Thx!

over 1 year ago ·
7068

great post, its funny how a lot of "developers" do just that they append elements while inside a loop not concerning themselves with repaints or reflows... thanks for posting!

over 1 year ago ·
7070

Thanks guys! I think reflows and repaints should be lifted "out of the hood," because right now, even in modern developer tools, it's hard to actually understand what causes them and how to track them down.

over 1 year ago ·
21255

Thanks man! It helped me improving my code!

over 1 year ago ·
27787

You may also want to move the 'el' declaration outside the loop and just set it with in the loop. It should also increase performance.

over 1 year ago ·
27798

According to the following, using the "innerText" property does not seem like a good idea (unless things have changed a lot in the past 3 years):
http://stackoverflow.com/a/19032002/5040168

over 1 year ago ·
28628

But what if I need to append multiple fragments into multiple divs? I mean not only single one as it was in example div.appendChild(fragment);
but something like:
div0.appendChild(fragment[0]);
div1.appendChild(fragment[1]);
div2.appendChild(fragment[2]);
...

over 1 year ago ·
29477

Hey!
I tried to build a jsperf to verify this claim, but I failed.
https://jsperf.com/fragment-no-clone
Maybe it is a recent optimization?
I see no reason for a browser to have to immediately trigger reflow/redraws anyways.
Cheers!

12 months ago ·
29612

Interestingly, it seems browsers these days have optimized, so that multiple writes to the DOM in the same synchronous code don't cause reflow, then finally the next frame will reflow and paint. In the perf test you linked, the appending version is the fastest for me in Chrome. It probably used to be slower than the DocumentFragment version, and the DocumentFragment version probably hasn't gotten slower, but the appendChild method is now faster! This is why some people suggest to batch reads and write and not mix them, otherwise a read can trigger a reflow, so interleaving them together causes many reflows.

11 months ago ·
31096

No no no and no.
the real answer is yes and no .
if you are going to create a div without any property yes appendChild is slighty faster (.on chrome only )
But please think like 5 sec .
looping with innerHTML += is really bad yes and really poor perf but .
just add a temporary variable looping over it and after it do an innerHTML = and yeah perf is faster or similar to appendChild.

In addition if you attemps to set property of DOM element before appendChild this last is way way slower than innerHTML.

the two test case :
https://jsperf.com/document-fragment-vs-innerhtml-vs-looped-appendchild/62 => innerHTML vs appendChild without setting prop
https://jsperf.com/document-fragment-vs-innerhtml-vs-looped-appendchild/63 => innerHTML vs appendChild with style prop

about 1 month ago ·