Search code examples
javascripthtmldomoptimizationreflow

Does createElement() trigger a reflow before the element is appended to the DOM? Confusing abt DocumentFragment behavior


I'm trying to figure out when exactly a reflow or repaint is triggered when an element is created.

The context for this is trying to understand if a DocumentFragment is necessary if the elements are not appended to extant items in the DOM tree until the end of the function. Here's an example:

HTML:

<body>
   <div id=target> </div>
</body>

JS:

const ul = document.CreateElement("ul")

for (let i=0; i<100000; i++) {

   let li = document.CreateElement("li")
   let li_text = document.CreateTextNode("Node #: " + i)

   li.appendChild(li_text)
   ul.appendChild(li)

}

document.getElementById("target").appendChild(ul)

In this example, is a reflow triggered every time an <li> is created in the loop? Or is only one reflow triggered after the <ul> is appended to <div id=target>?

If it's the former, would the appropriate way to prevent this multiple-reflowing be: (1) creating a document fragment, (2) appending a <ul> child to the fragment, (3) getting that <ul> and appending the <li> to it, then (4) appending the fragment to the <div>?

If it's the later... then what's the advantage of using a document fragment in contexts like this?

Context

I'm working on project which involves dynamically creating many lists -- I'm working on performance optimization, and am unsure how to monitor or test for this kind of behavior. Typically I test on Firefox, with apache hosting from a local directory.


Solution

  • Does createElement() trigger a reflow before the element is appended to the DOM?

    No. If the element isn't in the DOM, there's no (re)flow to calculate. (Re)flow relates to elements in the page being displayed.

    If it's the later... then what's the advantage of using a document fragment in contexts like this?

    In that specific case where you're only adding one top-level element, a fragment doesn't help. But if you wanted to build a structure with several elements at the top level, using a fragment lets you do that and then append them to the active DOM all at once rather than one at a time.

    For example, let's say hypothetically you already had that ul in the document and you wanted to append those 100,000 li elements to it. You could use a fragment so you only modify the active DOM once rather than 100,000 times:

    const frag = document.createDocumentFragment();
    for (let i = 0; i < 100_000; i++) {
        // Note: There's no need to call createTextNode explicitly here
        const li = document.createElement("li");
        li.textContent = `Node #: ${i}`;
        frag.appendChild(li);
    }
    
    document.getElementById("target-ul").appendChild(frag);
    <ul id="target-ul"></ul>