Last Updated: March 05, 2022
·
94.46K
· 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

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

over 1 year ago ·

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 ·

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 ·

Thanks man! It helped me improving my code!

over 1 year ago ·

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 ·

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 ·

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 ·

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!

over 1 year ago ·

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.

over 1 year ago ·

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

over 1 year ago ·