Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does cloneNode need to be used when appending a documentFragment?

I've been looking at using documentFragments in a Backbone.js app and was wondering why I see examples where "cloneNode" is used when appending the documentFragment to the parent DOM element.

An example can be seen here. If you look down at the DocumentFragment section you'll see this:

oFrag = document.createDocumentFragment();
for (var i = 0, imax = aElms.length; i < imax; i++) {
 oFrag.appendChild(aElms[i]);
}

o.innerHTML = '';
o.appendChild(oFrag.cloneNode(true));

Why does "oFrag" get cloned instead of just appending it? Another blog post doesn't use "cloneNode" (as a comparison).

like image 849
codecraig Avatar asked Dec 13 '12 10:12

codecraig


People also ask

What is cloneNode?

Definition and Usage. The cloneNode() method creates a copy of a node, and returns the clone. The cloneNode() method clones all attributes and their values. Set the deep parameter to true if you also want to clone descendants (children).

How do you duplicate an element?

You call the cloneNode() method on the element you want to copy. If you want to also copy elements nested inside it, pass in true as an argument. // Get the element var elem = document. querySelector('#elem1'); // Create a copy of it var clone = elem.

How do I copy a DOM?

Right click on a node and select Copy. You can paste in your code editor, or for prototyping, you can paste the DOM node elsewhere in the DOM tree. The pasted node is inserted as a child of the currently selected node.


3 Answers

If you append a documentFragment to an element, and you later clear the appended nodes from that element, your documentFragment will also be empty and cannot be reused anymore! Appending a clone of your documentFragment prevents this and allows multiple reuses of your documentFragment.

I assume the author of the jsperf snippet was testing for such a case.

Example: dropdowns with a parent-child relationship. Lets say you have a dropdown where you select a continent, and a second dropdown that lists all the countries in that continent. If you want to cache the created documentFragments with the option nodes after creation, using cloneNode is necessary. Imagine someone selects europe, then africa, then europe again: you can either recreate the entire documentfragment, of cache it.

I created a jsperf snippet to illustrate the performance difference of recreating the documentFragments vs caching and cloning the fragments:

http://jsperf.com/documentfragment-cache-vs-recreate

like image 101
Davy Avatar answered Oct 13 '22 21:10

Davy


Your first link refers to the blog post where the autor uses document.getElementsByTagName instead of document.getElementById, like in test case. If you want a multiple elements (namely: divs) to be given the same documentFragment, you must clone it:

If child is a reference to an existing node in the document, appendChild moves it from its current position to the new position (i.e. there is no requirement to remove the node from its parent node before appending it to some other node).

This also means that a node can't be in two points of the document simultaneously. So if the node already has a parent, it is first removed, then appended at the new position.

via MDN

Most likely the author (or someone else) copy-pasted the code without taking this into consideration. Try it yourself - you can use appendChild without cloneNode and everything works fine.

Another possibility is that someone who created this test case on jsperf didn't get much how preparation code works and was worried that the very first test will empty aElms array and it won't work anymore. In fact preparation code is executed before each timed iteration, so there's no need to be worried about its contents.

The last thing may the performance concern. If you really want to test the real insertion, you need to clone the node. Otherwise, you'll test tree reattachment instead (see MDN link above).

Also please note that cloning destroys event listeners.

Happy fragmentin'! ;)

like image 40
oleq Avatar answered Oct 13 '22 20:10

oleq


I'm not exactly sure, but in the context of the link you provided (performance testing) the oFrag.cloneNode(true) might be a safeguard against reusing the elements already added in DOM in previous runs of the loop, which would result in way faster execution of the test.

I see no reason to use it in normal use cases of documentFragments.

like image 23
JNissi Avatar answered Oct 13 '22 19:10

JNissi