Consider these three versions of appending li
s to a ul
:
Naive Version (20% slower):
var ul = document.getElementById('targetUl');
for (var i = 0; i < 200; i++) {
var li = document.createElement('li');
li.innerHTML = Math.random();
ul.appendChild(li);
}
Using a JavaScript Fragment (4% slower):
var ul = document.getElementById('targetUl'),
fragment = document.createDocumentFragment();
for (var i = 0; i < 200; i++) {
var li = document.createElement('li');
li.innerHTML = Math.random();
fragment.appendChild(li);
}
ul.appendChild(fragment);
Appending to an element not yet in the DOM (1.26% faster):
var ul = document.createElement('ul'),
div = document.getElementById('targetDiv');
for (var i = 0; i < 200; i++) {
var li = document.createElement('li');
li.innerHTML = Math.random();
ul.appendChild(li);
}
div.appendChild(ul);
Why is appending to a DOM element held in memory faster than appending to a Fragment
? Since fragment
was created for this sole purpose shouldn't it be faster? Are they're any advantages to using a fragment
over an element held in memory other than not having to include a top level element before appending?
Check the test output from jsperf:
Consider these three versions of appending li
s to a ul
:
Naive Version (20% slower):
var ul = document.getElementById('targetUl');
for (var i = 0; i < 200; i++) {
var li = document.createElement('li');
li.innerHTML = Math.random();
ul.appendChild(li);
}
Using a JavaScript Fragment (4% slower):
var ul = document.getElementById('targetUl'),
fragment = document.createDocumentFragment();
for (var i = 0; i < 200; i++) {
var li = document.createElement('li');
li.innerHTML = Math.random();
fragment.appendChild(li);
}
ul.appendChild(fragment);
Appending to an element not yet in the DOM (1.26% faster):
var ul = document.createElement('ul'),
div = document.getElementById('targetDiv');
for (var i = 0; i < 200; i++) {
var li = document.createElement('li');
li.innerHTML = Math.random();
ul.appendChild(li);
}
div.appendChild(ul);
Why is appending to a DOM element held in memory faster than appending to a Fragment
? Since fragment
was created for this sole purpose shouldn't it be faster? Are they're any advantages to using a fragment
over an element held in memory other than not having to include a top level element before appending?
Check the test output from jsperf: http://jsperf./javascript-fragments-tests
Share asked Jul 22, 2014 at 3:27 agcontiagconti 18.1k17 gold badges84 silver badges118 bronze badges 4- Without reference to the underlying code or design, whatever answer you get is guesswork. Mine is that a fragment is a generic container for any DOM element, whereas a UL is quite specific and can only have LI child elements, so there's work that a fragment must do when elements are appended that a UL doesn't. I would rate ±4% as not significant. – RobG Commented Jul 22, 2014 at 3:35
- Don't worry too hard over micro optimization – Sterling Archer Commented Jul 22, 2014 at 3:36
- What would make a Fragment faster? (Asking hypothetically what optimizations could be done in a Fragment vs. a regular DOM element) – JKillian Commented Jul 22, 2014 at 3:42
- @JKillian Its supposed to be a minimal document object thats designed for this exact action. I'm not sure what optimizations they could have used to make this happen. – agconti Commented Jul 22, 2014 at 3:48
2 Answers
Reset to default 8It is a bit more work to insert multiple children from a document fragment (particularly when your test has 200 children) than it is to insert a single parent <ul>
tag.
So, with the fragment, you're reparenting 200 <li>
elements from the fragment to your <ul>
tag in the DOM.
With your last code block, you're just reparenting the one <ul>
tag by inserting it into the DOM.
So, in your particular example, using the document fragment creates more work for the insertion into the DOM than the way you run your last example that just has to insert the single <ul>
tag.
The fragment has its tactical advantages when you want to keep track of a whole bunch of elements at the same level and then insert them with one line of code and you the parent is already in the DOM. But, it isn't always the fastest way to do things vs. a scenario where you can collect all the items out of the DOM at the same level under their actual parent node and then insert just that parent node.
My speculation is...
For Naive version. The loop when appending elements in the DOM gets bigger and longer. As more elements are loaded in the ul tag existing in the DOM the longer it takes to process the succeeding elements to be appended. This one takes longer because you are modifying a tag that already exists in the DOM.
For Javascript Fragment The fragment is non-existent in the HTML document yet and is only appended to ul after inserting a series of li in the fragment. There is only backend processing that is happening in the loop part then inserts the fragment that contains the multiple lis in the DOM. and ofcourse, since the ul is existing in the DOM there's still a loop involved because it takes some time to adopt the child.
For appending to an element not yet in DOM. This one mostly works on the backend and makes the UI interpreter exert less effort since it's like adding another paper on top of a pile of papers(Everything was worked on the paper to be added on top of the pile of papers).
My explanation might not be accurate but at least I'm sharing an idea. This has been one of the biggest problems of us Game developers.