Czy powinienem używać document.createDocumentFragment czy document.createElement

97

I został czytania o fragmenty dokumentów i DOM reflow i zastanawiał się, jak document.createDocumentFragmentróżni się od document.createElement, jak to wygląda jak żadna z nich nie istnieje w DOM aż dołączyć je do elementu DOM.

Zrobiłem test (poniżej) i wszystkie z nich zajęły dokładnie tyle samo czasu (około 95 ms). Przypuszczalnie może to być spowodowane tym, że żaden z elementów nie został zastosowany w stylu, więc może nie było ponownego przepływu.

W każdym razie, w oparciu o poniższy przykład, dlaczego powinienem używać createDocumentFragmentzamiast createElementwstawiania do DOM i jaka jest różnica między nimi.

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
źródło

Odpowiedzi:

98

Różnica polega na tym, że fragment dokumentu skutecznie znika po dodaniu go do DOM. Dzieje się tak, że wszystkie węzły potomne fragmentu dokumentu są wstawiane w miejscu w DOM, w którym wstawiasz fragment dokumentu, a sam fragment dokumentu nie jest wstawiany. Sam fragment nadal istnieje, ale teraz nie ma dzieci.

Pozwala to na jednoczesne wstawianie wielu węzłów do DOM:

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
źródło
3
Dzięki za odpowiedzi. Mówisz, że pozwala na wielokrotne wstawianie w tym samym czasie, ale mogę to osiągnąć za pomocą doc.createElement. Jedyną różnicą było to, że najpierw musiałem zawinąć elementy w znacznik <span>, a następnie wstawić <span> do DOM. Czy dlatego powinienem używać createDocumentFragment? Aby uniknąć wstawiania niepotrzebnych elementów do DOM?
screenm0nkey
4
Tak, to zdecydowanie jeden z powodów, dla których warto go używać. Ponadto fragment dokumentu może zawierać dowolny rodzaj węzła, podczas gdy element nie.
Tim Down
3
Właściwie fragment nie „znika”; przeglądarka przenosi swoje childNodes do DOM. Tak więc fragment nadal będzie istniał, ale po wstawieniu będzie pusty.
inf3rno
1
@ inf3rno: Stąd moje użycie słowa „skutecznie” i następujące po nim wyjaśnienie, które jest bardzo podobne do twojego. Przyznaję, że powinienem był powiedzieć wyraźnie w odpowiedzi, że fragment nadal istnieje bez węzłów potomnych.
Tim Down
1
@TimDown dzięki za odpowiedź! Jeśli dobrze zrozumiem, jeśli chodzi o wydajność, użycie createFragmenti createElementprzechowywanie w pamięci, ma mniej więcej taki sam efekt, jak oba zbiorcze aktualizowanie modelu DOM zamiast wielokrotnej iteracyjnej aktualizacji. Chociaż główną zaletą programu createFragmentjest to, że zapewnia elastyczność wyboru elementów podrzędnych do bezpłatnego dołączenia? Popraw mnie, jeśli się myliłem.
Xlee,
9

Kolejna bardzo ważna różnica między tworzeniem elementu a fragmentem dokumentu:

Kiedy tworzysz element i dołączasz go do DOM, element jest dołączany do DOM, podobnie jak elementy podrzędne.

Do fragmentu dokumentu dołączane są tylko dzieci.

Weźmy przykład:

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>

co skutkuje tym zniekształconym kodem HTML (dodano spacje)

<ul id="ul_test">
  <li>Document Fragment</li>
  <div><li>Inside Div</li></div>
</ul>
Jeremy J Starcher
źródło