Soll ich document.createDocumentFragment oder document.createElement verwenden?

97

Ich habe über Dokumentfragmente und DOM-Reflow gelesen und mich gefragt, wie document.createDocumentFragmentunterschiedlich es ist, document.createElementda es so aussieht, als ob keines von beiden im DOM vorhanden ist, bis ich sie an ein DOM-Element anhänge.

Ich habe einen Test gemacht (siehe unten) und alle haben genau die gleiche Zeit gebraucht (ca. 95 ms). Vermutlich könnte dies daran liegen, dass auf keines der Elemente ein Stil angewendet wurde, sodass möglicherweise kein Reflow möglich ist.

Wie auch immer, basierend auf dem folgenden Beispiel, warum sollte ich createDocumentFragmentanstelle des createElementEinfügens in das DOM verwenden und was ist der Unterschied zwischen den beiden.

var htmz = "<ul>";
for (var i = 0; i < 2001; i++) {
    htmz += '<li><a href="#">link ' + i + '</a></li>';
}
htmz += '<ul>';

//createDocumentFragment
console.time('first');
var div = document.createElement("div");
div.innerHTML = htmz;
var fragment = document.createDocumentFragment();
while (div.firstChild) {
    fragment.appendChild(div.firstChild);
}
$('#first').append(fragment);
console.timeEnd('first');

//createElement
console.time('second');
var span = document.createElement("span");
span.innerHTML = htmz;
$('#second').append(span);
console.timeEnd('second');


//jQuery
console.time('third');
$('#third').append(htmz);
console.timeEnd('third');
screenm0nkey
quelle

Antworten:

98

Der Unterschied besteht darin, dass ein Dokumentfragment effektiv verschwindet, wenn Sie es dem DOM hinzufügen. Was passiert ist, dass alle untergeordneten Knoten des Dokumentfragments an der Stelle im DOM eingefügt werden, an der Sie das Dokumentfragment einfügen, und das Dokumentfragment selbst nicht eingefügt wird. Das Fragment selbst existiert weiterhin, hat aber jetzt keine Kinder.

Auf diese Weise können Sie mehrere Knoten gleichzeitig in das DOM einfügen:

var frag = document.createDocumentFragment();
var textNode = frag.appendChild(document.createTextNode("Some text"));
var br = frag.appendChild(document.createElement("br"));
var body = document.body;
body.appendChild(frag);
alert(body.lastChild.tagName); // "BR"
alert(body.lastChild.previousSibling.data); // "Some text"
alert(frag.hasChildNodes()); // false
Tim Down
quelle
3
Danke für die Antwort. Sie sagen, dass mehrere Einfügungen gleichzeitig möglich sind, aber ich kann dies mit doc.createElement erreichen. Der einzige Unterschied bestand darin, dass ich die Elemente zuerst in ein <span> -Tag einschließen und dann dieses <span> in das DOM einfügen musste. Sollte ich deshalb createDocumentFragment verwenden? Um zu vermeiden, dass unnötige Elemente in das DOM eingefügt werden?
screenm0nkey
4
Ja, das ist definitiv ein Grund, es zu benutzen. Ein Dokumentfragment kann auch jede Art von Knoten enthalten, während ein Element dies möglicherweise nicht tut.
Tim Down
3
Tatsächlich "verschwindet" das Fragment nicht; Der Browser verschiebt seine childNodes in das DOM. Das Fragment bleibt also bestehen, ist aber nach dem Einfügen leer.
inf3rno
1
@ inf3rno: Daher meine Verwendung des Wortes "effektiv" und die folgende Erklärung, die Ihrer sehr ähnlich ist. Ich gebe zu, dass ich in der Antwort ausdrücklich hätte sagen sollen, dass das Fragment weiterhin ohne untergeordnete Knoten existiert.
Tim Down
1
@ TimDown danke für deine Antwort! Wenn ich Ihren Standpunkt in Bezug auf Leistung, Verwendung createFragmentund createElementSpeicherplatz richtig verstehe, hat dies ungefähr den gleichen Effekt, da beide das DOM stapelweise aktualisiert haben, anstatt es mehrmals iterativ zu aktualisieren. Der Hauptvorteil von createFragmentist, dass es Ihnen die Flexibilität bietet, die untergeordneten Elemente auszuwählen, die Sie kostenlos anhängen möchten. Korrigieren Sie mich, wenn ich falsch lag.
Xlee
9

Ein weiterer sehr wichtiger Unterschied zwischen dem Erstellen eines Elements und eines Dokumentfragments:

Wenn Sie ein Element erstellen und an das DOM anhängen, wird das Element an das DOM sowie an die untergeordneten Elemente angehängt.

Bei einem Dokumentfragment werden nur die untergeordneten Elemente angehängt.

Nehmen Sie den Fall von:

var ul = document.getElementById("ul_test");


// First. add a document fragment:


(function() {
  var frag = document.createDocumentFragment();
  
  
  var li = document.createElement("li");
  li.appendChild(document.createTextNode("Document Fragment"));
  frag.appendChild(li);
  
  ul.appendChild(frag);
  console.log(2);
}());

(function() {
  var div = document.createElement("div");
  
  
  var li = document.createElement("li");
  li.appendChild(document.createTextNode("Inside Div"));
   div.appendChild(li);
  
  ul.appendChild(div);
}());
Sample List:
<ul id="ul_test"></ul>

was zu diesem fehlerhaften HTML führt (Leerzeichen hinzugefügt)

<ul id="ul_test">
  <li>Document Fragment</li>
  <div><li>Inside Div</li></div>
</ul>
Jeremy J Starcher
quelle