Should I use document.createDocumentFragment or document.createElement
Asked Answered
D

3

118

I was reading about document fragments and DOM reflow and wondered how document.createDocumentFragment differed from document.createElement as it looks like neither of them exist in the DOM until I append them to a DOM element.

I did a test (below) and all of them took exactly the same amount of time (about 95ms). At a guess this could possibly be due to there being no style applied to any of the elements, so no reflow maybe.

Anyway, based on the example below, why should I use createDocumentFragment instead of createElement when inserting into the DOM and whats the differnce between the two.

var htmz = "<ul>";
for (var i = 0; i < 2001; i++) {
    htmz += '<li><a href="#">link ' + i + '</a></li>';
}
htmz += '<ul>';

//createDocumentFragment
console.time('first');
var div = document.createElement("div");
div.innerHTML = htmz;
var fragment = document.createDocumentFragment();
while (div.firstChild) {
    fragment.appendChild(div.firstChild);
}
$('#first').append(fragment);
console.timeEnd('first');

//createElement
console.time('second');
var span = document.createElement("span");
span.innerHTML = htmz;
$('#second').append(span);
console.timeEnd('second');


//jQuery
console.time('third');
$('#third').append(htmz);
console.timeEnd('third');
Donegal answered 3/8, 2010 at 13:53 Comment(0)
B
115

The difference is that a document fragment effectively disappears when you add it to the DOM. What happens is that all the child nodes of the document fragment are inserted at the location in the DOM where you insert the document fragment and the document fragment itself is not inserted. The fragment itself continues to exist but now has no children.

This allows you to insert multiple nodes into the DOM at the same time:

var frag = document.createDocumentFragment();
var textNode = frag.appendChild(document.createTextNode("Some text"));
var br = frag.appendChild(document.createElement("br"));
var body = document.body;
body.appendChild(frag);
alert(body.lastChild.tagName); // "BR"
alert(body.lastChild.previousSibling.data); // "Some text"
alert(frag.hasChildNodes()); // false
Barre answered 3/8, 2010 at 14:4 Comment(6)
Thanks for the response. You say that it allows for multiple insert at the same time but I can achieve that using doc.createElement. The only difference being I had to wrap the elements in a <span> tag first and then insert that <span> into the DOM. Is that why I should use createDocumentFragment? To avoid unnecessary elements being inserted into the DOM?Donegal
Yes, that's definitely one reason to use it. Also, a document fragment may contain any kind of node whereas an element may not.Barre
Actually the fragment does not "disappear"; the browser moves the its childNodes to the DOM. So the fragment will still exist, but it will be empty after the insertion.Render
@inf3rno: Hence my use of the word "effectively" and the explanation that follows, which is much the same as yours. I concede that I should have said explicitly in the answer that the fragment continues to exist with no child nodes.Barre
@TimDown thanks for your answer! If i get your point right, regarding performance, use createFragment and createElement in memory has roughly the same effect as they both batch updated the DOM instead of iteratively update for multiple times. While the main benefit of createFragment is that it offers you the flexibility to choose whatever child elements to append for free? Correct me if i were wrong.Mattins
Consider the DocumentFragment as a temporary host parent element for multiple children elements.Trishtrisha
A
16

Another very important difference between creating an element and a document fragment:

When you create an element and append it to the DOM, the element is appended to the DOM, as well as the children.

With a document fragment, only the children are appended.

Take the case of:

var ul = document.getElementById("ul_test");


// First. add a document fragment:


(function() {
  var frag = document.createDocumentFragment();
  
  
  var li = document.createElement("li");
  li.appendChild(document.createTextNode("Document Fragment"));
  frag.appendChild(li);
  
  ul.appendChild(frag);
  console.log(2);
}());

(function() {
  var div = document.createElement("div");
  
  
  var li = document.createElement("li");
  li.appendChild(document.createTextNode("Inside Div"));
   div.appendChild(li);
  
  ul.appendChild(div);
}());
Sample List:
<ul id="ul_test"></ul>

which results in this malformed HTML (whitespace added)

<ul id="ul_test">
  <li>Document Fragment</li>
  <div><li>Inside Div</li></div>
</ul>
Autostability answered 14/5, 2016 at 0:20 Comment(0)
G
5

You can think of a DocumentFragment as a virtual DOM. It's not connected to the DOM and unlike elements, it has no parent, EVER. You can then interact with the fragment as if it's a virtual document object. It's all in memory.

It's really helpful to use fragments when you have many DOM manipulations to make or style changes, because those will trigger reflows and repaints - expensive operations on the DOM that can slow the page load down.

The bonus you get with fragment is that it triggers only one reflow when the fragment is inserted into the DOM, no matter how many children it contains.

DocumentFragment is not an element or a Node. It's a stripped down Document object with a reduced set of properties and methods.

If you've ever heard of the virtual DOM with React, they are making heavy use of DocumentFragments in the ReactDOM library. That's why it's so performant.

Goldschmidt answered 22/7, 2022 at 18:17 Comment(1)
Surely that’s dependent on how you use it. If I createElement and append loads of children, that won’t cause any reflows or paints until I append that first/original element to an existing element that is in the main dom and displayed? Or am I misunderstanding? Does the very nature of calling createElement cause a reflow straight away because it’s immediacy added to the dom at its root?Straley

© 2022 - 2024 — McMap. All rights reserved.