DocumentFragment: what it is and how to (not) fight it

Disclaimer
It seems that I am starting a new series of articles - a bit boring and purely utilitarian. They will contain explanations of the points that often cause difficulties for my students. If you are a solid web developer, you will most likely not be interested. If you expect perversions in the power of "Friday JS", they will not be here, alas.


One of the things students regularly have problems understanding is DocumentFragment. In general, I can not blame them for it. With external simplicity, it has several unobvious and even counterintuitive properties. In this article I want to collect everything that a novice needs to know about him.

image

What it is


A DocumentFragment is a container that can contain an arbitrary number of DOM elements. If quite simply, you can imagine it as a bucket. The elements are folded into it so that at the right moment they can be dumped at once where necessary.

How to create


Elementary.

var fragment = document.createDocumentFragment(); 

There are also other ways, but about them below.

Why do you need


As I wrote above, in order to store DOM elements. “But they can be stored in a normal diva,” the reader might argue. True, however, the fragment has a unique property that makes it the best candidate for this role. Consider the following code:

 var fragment = document.createDocumentFragment(); var parentDiv = document.createElement("div"); var div1 = document.createElement("div"); var div2 = document.createElement("div"); fragment.appendChild(div1); fragment.appendChild(div2); //   parentDiv.appendChild(fragment); console.log(parentDiv.children); 

What will the console tell us? A person who is not familiar with DocumentFragment might think that parentDiv 'will have one child element - fragment . But in fact, he will have two child elements - div1 and div2 . The point is that the fragment itself is not a DOM element, it is only a container for DOM elements. And when it is passed as an argument to methods of type appendChild or insertBefore , it is not embedded in the DOM tree, but instead it embeds its contents.

And yet, why do you need it?


The “bucket” property is, of course, good, but how is this useful in practice? DocumentFragment has two main areas of use.

1. Storing pieces of HTML that have no common ancestor.

There are situations when we need to replace the contents of an element, but do not touch the element itself. Suppose we use event delegation, and all event handlers that occur on internal elements are hung on an external div. In this case, we are ideally suited DocumentFragment:

 div.innerHTML = ""; div.appendChild(fragmentWithAllContent); 

“But can we just add elements to the div as soon as they are created?” Asks a corrosive reader. We can, but this is not worth doing, and here is why.

2. Improved performance in the case of multiple inserts.

The fact is that every time we change something in the active DOM tree, the browser has to perform a bunch of calculations. More information about this can be found here , for example. In this article we will limit ourselves to mentioning that there is such a terrible beast - reflow. When we add an element to the page, this beast wakes up and eats a piece of CPU time. If we in turn add one hundred elements, the beast will wake up a hundred times and make a “bite” a hundred times. For the user, this may already be quite tangible "hang".

When we add an element to the DocumentFragment, it does not cause a reflow, because the fragment is not (and in principle cannot be) part of the active DOM tree. And the most important thing: when we insert the contents of a fragment using appendChild or other similar methods, no matter how many elements are inside the fragment, reflow is called only once .

For clarity, I made a simple benchmark so that the reader could personally see the difference.

Upd: comrade nuit told that for modern Chrome my words are no longer true. In it, reflow is not executed earlier than necessary, and thanks to this, the code without DocumentFragment actually works faster , and with other browsers, not everything is so obvious. So before deciding whether to use fragments, profiling and research of the site’s target audience is necessary.

Nuances


There are two features due to which beginners often have difficulty using fragments. First, as I wrote above, the fragment is not a DOM element . This means that it lacks many familiar methods and properties, in particular, innerHTML . Therefore, you can not just turn the string into the contents of the fragment. How to do this is not easy, will be discussed below.

The second feature: the fragment with the use of "spoils". More precisely - emptied. When we do div.appendChild(fragment) , all the child elements of the fragment are transferred to the div . And since an element cannot have more than one parent, this means that they are withdrawn from the fragment! To avoid this behavior when it is undesirable, you can use cloneNode .

<Template> tag


There is one place where you can meet DocumentFragment, without creating it through JS. This is the content property of the template element.

The <template> designed specifically to store chunks of HTML code, but ahead of time not to load the browser with them. What is inside this tag does not become part of the active DOM tree. In particular (newcomers often querySelector with this too), they cannot be found using the querySelector . Elements created from the HTML code inside the <template> tag do not become children of it. Instead, JavaScript can access them through the content property, which is - surprise! - just DocumentFragment'om.

Using the template element, you can create a fragment from a string:

 function createFragmentFromString(str){ var template = document.createElement("template"); template.innerHTML = str; return template.content; } 

Epilogue


If you are new to web development, I hope you have learned a lot. If you are an experienced developer, you may want to add something to this article, in that case feel free to write about it in the comments. Thank you for reading, and have a nice day.

Source: https://habr.com/ru/post/413287/


All Articles