A document fragment is a fragment of a Document Object Model (DOM) tree, a chunk of tree that's separated from the rest of the DOM.
Before going further, let's talk about browser reflow and how it affects performance.
According to the google developers, reflow is the name of the web browser process for re-calculating the positions and geometries
of elements in the document, for the purpose of re-rendering part or all of the document.
Browser reflow can be caused by resizing the window,
changing the font, adding or removing a stylesheet, activation of a css psuedo-class, a script manipulating the DOM amongst others.
There are are several events other events that could trigger a browser reflow, but our main focus is the DOM manipulation from the script file.
Let's take for example the following data format gotten from restcountries api and we need to display each country, with its flag;
const countries = [
{
name: "Afghanistan",
population: 27657145,
flag: "https://restcountries.eu/data/afg.svg",
},
{
name: "Åland Islands",
population: 28875,
flag: "https://restcountries.eu/data/ala.svg",
},
{
name: "Albania",
population: 2886026,
flag: "https://restcountries.eu/data/alb.svg",
},
];
A simple approach to this would be:
- loop over each element in the array
- create a new element
- append to an element in the DOM.
Here's how we would go about that in code.
// Select the parent element
const parentElement = document.querySelector('.countries');
// Loop over the array of countries and create each element
countries.forEach(country => {
// Create a new div element
const countryCard = document.createElement('div');
// Create a new image element
const img = document.createElement('img');
// Set the src attribute of the image to the flag value from the data
img.src = country.flag;
// Attach the image to the div we initially created
countryCard.appendChild(img);
// Attach the card to parent element
parentElement.appendChild(countryCard);
});
Seems pretty simple and straightforward, and there seems to be nothing to worry about....if it's not broken, why fix it right?? 😃😃.
But under the hood, for every time we append the countryCard to the parentElement, we're causing a browser reflow. We might not notice any
glitch or drastic decline in performance in this case and that's because we only have three elements in the array, now imagine we had to the same thing for
all the countries and their individual states...you see where this is going?
Lucky for us, the browser provides a DocumentFragment
object for us. As explained earlier, the document fragment is basically an interface
that represents a minimal document object (MDN).
It allows us perform actions we would normally perform on the actual DOM
but without the usual side effects, so we can easily create and append new elements without worrying about the numerous browser reflows that could
occur, and after we're done, we attach the fragment back into the DOM, hence only causing a single browser reflow as opposed to the hundreds or thousands of reflows we could have otherwise caused if we didn't use the fragment.
Now let's repeat the same thing we did above, but this time using the document fragment. The first thing we need to do is create the fragment.
That can be done using the DocumentFragment
constructor or the createDocumentFragment
method.
let fragment = new DocumentFragment();
// or let fragment = document.createDocumentFragment();
const parentElement = document.querySelector('.countries');
// Loop over the array of countries and create each element
countries.forEach(country => {
// Create a new div element
const countryCard = document.createElement('div');
// Create a new image element
const img = document.createElement('img');
// Set the src attribute of the image to the flag value from the data
img.src = country.flag;
// Attach the image to the div we initially created
countryCard.appendChild(img);
// Append card to fragment element
fragment.appendChild(countryCard);
});
// After iterating, we then insert fragment contents into the DOM
parentElement.appendChild(fragment);
Something really interesting about the DocumentFragment
is that the contents of the fragment are actually moved into the DOM, leaving behind
an empty DocumentFragment
.
So you don't really have to worry about memory consumption....pretty awesome right? 😉😉
The document fragment is just one of many ways we could improve browser performance. There are several other techniques we could use to improve
performance of our web application
Top comments (13)
Beside the additional div in the Dom tree, what is the different between creating the fragment and creating a div (using createElement) and appending all of the elements to it before finally appending it to the Dom? As long as the parent div is not in the Dom there will be no reflows, right?
Well, as you rightly mentioned, there's the fact that you'd be creating an additional element, which might or might not be what you wanted to achieve.
Also when using fragments, the children are effectively moved into the DOM and leaves behind an empty fragment.
But then again, they both serve the same purpose, and whatever works for you is fine. Some people would suggest using the createElement cause it's faster, some would say to use the DocumentFragment cause it was built for this
If this has to be done multiple times, it will only create an untidy DOM tree with lots of empty divs. Then this will affect accessing DOM elements. For the same reason react also introduced Fragments.
Thanks for writing this up. It was really great.
This was such a great article that it inspired me to create a simple example CodePen for it.
You can check it out at : codepen.io/raddevus/pen/WNQbOpK
It looks like this:
This is really amazing. Good work with the display 👌🏻
We can store the elements in array and after completing loop call append method with array.
`
`
function getListContent() {
let result = [];
for(let i=1; i<=3; i++) {``
let li = document.createElement('li');
li.append(i);
result.push(li);
}
return result;
}
ul.append(...getListContent()); // append + "..." operator = friends!
``Performance is such an important issue so this is just great. I particularly love that the fragment acts as a temporary storage and empties itself automatically after use.
This is seriously brilliant. I needed this.
Really glad I could be of help
Pretty neat writeup. I didn't for once consider optimizing for reflow
Nice one
Thanks a lot
🤔 I 🤔 using TEMPLATE 🏷 can alleviate some of this too.