Devo usare document.createDocumentFragment o document.createElement


97

Stavo leggendo di frammenti di documenti e di reflow DOM e mi chiedevo in che cosa document.createDocumentFragmentdifferissero dal document.createElementfatto che nessuno di loro esisteva nel DOM fino a quando non li aggiungo a un elemento DOM.

Ho fatto un test (sotto) e tutti hanno impiegato esattamente la stessa quantità di tempo (circa 95 ms). Probabilmente ciò potrebbe essere dovuto al fatto che non vi è alcuno stile applicato a nessuno degli elementi, quindi forse nessun riflusso.

Ad ogni modo, in base all'esempio seguente, perché dovrei usare createDocumentFragmentinvece di createElementquando inserisco nel DOM e qual è la differenza tra i due.

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');

Risposte:


98

La differenza è che un frammento di documento scompare effettivamente quando lo aggiungi al DOM. Quello che succede è che tutti i nodi figli del frammento di documento vengono inseriti nella posizione nel DOM in cui inserisci il frammento di documento e il frammento di documento stesso non viene inserito. Il frammento stesso continua ad esistere ma ora non ha figli.

Ciò ti consente di inserire più nodi nel DOM contemporaneamente:

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

3
Grazie per la risposta. Dici che consente più inserimenti contemporaneamente, ma posso ottenerlo usando doc.createElement. L'unica differenza è che dovevo prima avvolgere gli elementi in un tag <span> e poi inserire quello <span> nel DOM. È per questo che dovrei usare createDocumentFragment? Per evitare che elementi non necessari vengano inseriti nel DOM?
screenm0nkey

4
Sì, questo è sicuramente un motivo per usarlo. Inoltre, un frammento di documento può contenere qualsiasi tipo di nodo mentre un elemento no.
Tim Down

3
In realtà il frammento non "scompare"; il browser sposta i suoi childNode nel DOM. Quindi il frammento esisterà ancora, ma sarà vuoto dopo l'inserimento.
inf3rno

1
@ inf3rno: da qui il mio uso della parola "efficacemente" e la spiegazione che segue, che è più o meno la tua. Ammetto che avrei dovuto dire esplicitamente nella risposta che il frammento continua ad esistere senza nodi figlio.
Tim Down

1
@TimDown grazie per la tua risposta! Se ho ragione, per quanto riguarda le prestazioni, l'uso createFragmente la createElementmemoria ha più o meno lo stesso effetto in quanto entrambi hanno aggiornato in batch il DOM invece di aggiornarlo in modo iterativo per più volte. Anche se il vantaggio principale createFragmentè che ti offre la flessibilità di scegliere qualsiasi elemento figlio da aggiungere gratuitamente? Correggimi se ho sbagliato.
Xlee

9

Un'altra differenza molto importante tra la creazione di un elemento e un frammento di documento:

Quando crei un elemento e lo aggiungi al DOM, l'elemento viene aggiunto al DOM, così come i figli.

Con un frammento di documento, vengono aggiunti solo i figli.

Prendi il caso di:

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>

che si traduce in questo HTML non valido (spazio bianco aggiunto)

<ul id="ul_test">
  <li>Document Fragment</li>
  <div><li>Inside Div</li></div>
</ul>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.