Dois-je utiliser document.createDocumentFragment ou document.createElement

97

Je lisais à propos des fragments de document et de la refusion DOM et je me suis demandé en quoi il était document.createDocumentFragmentdifférent document.createElementcar il semble qu'aucun d'eux n'existait dans le DOM jusqu'à ce que je les ajoute à un élément DOM.

J'ai fait un test (ci-dessous) et tous ont pris exactement le même temps (environ 95 ms). À une supposition, cela pourrait être dû au fait qu'aucun style n'est appliqué à l'un des éléments, donc pas de redistribution peut-être.

Quoi qu'il en soit, sur la base de l'exemple ci-dessous, pourquoi devrais-je utiliser createDocumentFragmentau lieu de createElementlors de l'insertion dans le DOM et quelle est la différence entre les deux.

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
la source

Réponses:

98

La différence est qu'un fragment de document disparaît effectivement lorsque vous l'ajoutez au DOM. Ce qui se passe, c'est que tous les nœuds enfants du fragment de document sont insérés à l'emplacement dans le DOM où vous insérez le fragment de document et le fragment de document lui-même n'est pas inséré. Le fragment lui-même continue d'exister mais n'a plus d'enfants.

Cela vous permet d'insérer plusieurs nœuds dans le DOM en même temps:

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
la source
3
Merci pour la réponse. Vous dites que cela permet plusieurs insertions en même temps, mais je peux y parvenir en utilisant doc.createElement. La seule différence était que je devais d'abord envelopper les éléments dans une balise <span>, puis insérer cette <span> dans le DOM. Est-ce pourquoi je devrais utiliser createDocumentFragment? Pour éviter que des éléments inutiles ne soient insérés dans le DOM?
screenm0nkey
4
Oui, c'est certainement une des raisons de l'utiliser. De plus, un fragment de document peut contenir n'importe quel type de nœud alors qu'un élément ne peut pas.
Tim Down
3
En fait, le fragment ne "disparaît" pas; le navigateur déplace ses childNodes vers le DOM. Le fragment existera donc toujours, mais il sera vide après l'insertion.
inf3rno
1
@ inf3rno: D'où mon utilisation du mot «effectivement» et l'explication qui suit, qui est sensiblement la même que la vôtre. J'admets que j'aurais dû dire explicitement dans la réponse que le fragment continue d'exister sans nœuds enfants.
Tim Down
1
@TimDown merci pour votre réponse! Si je comprends bien, en ce qui concerne les performances, l'utilisation createFragmentet la createElementmémoire ont à peu près le même effet car ils ont tous deux mis à jour le DOM par lots au lieu de le mettre à jour de manière itérative plusieurs fois. Alors que le principal avantage de createFragmentest qu'il vous offre la possibilité de choisir les éléments enfants à ajouter gratuitement? Corrigez-moi si je me suis trompé.
Xlee
9

Une autre différence très importante entre la création d'un élément et un fragment de document:

Lorsque vous créez un élément et l'ajoutez au DOM, l'élément est ajouté au DOM, ainsi que les enfants.

Avec un fragment de document, seuls les enfants sont ajoutés.

Prenons le cas de:

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>

ce qui entraîne ce HTML malformé (espace ajouté)

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