Должен ли я использовать document.createDocumentFragment или document.createElement

97

Я читал о фрагментах документа и перекомпоновке DOM и задавался вопросом, чем они document.createDocumentFragmentотличаются от того, document.createElementкак кажется, что ни один из них не существует в DOM, пока я не добавлю их в элемент DOM.

Я провел тест (ниже), и все они заняли одинаковое количество времени (около 95 мс). Предположительно, это могло быть из-за того, что ни к одному из элементов не применялся стиль, поэтому возможно и никакого перекомпоновки.

В любом случае, исходя из приведенного ниже примера, почему я должен использовать его createDocumentFragmentвместо createElementвставки в DOM и в чем разница между ними.

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
источник

Ответы:

98

Разница в том, что фрагмент документа фактически исчезает, когда вы добавляете его в DOM. Что происходит, так это то, что все дочерние узлы фрагмента документа вставляются в то место в DOM, куда вы вставляете фрагмент документа, а сам фрагмент документа не вставляется. Сам фрагмент продолжает существовать, но теперь не имеет дочерних элементов.

Это позволяет вам одновременно вставлять несколько узлов в 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
Тим Даун
источник
3
Спасибо за ответ. Вы говорите, что он позволяет выполнять несколько вставок одновременно, но я могу добиться этого с помощью doc.createElement. Единственная разница в том, что мне пришлось сначала обернуть элементы тегом <span>, а затем вставить этот <span> в DOM. Вот почему я должен использовать createDocumentFragment? Чтобы избежать вставки ненужных элементов в DOM?
screenm0nkey
4
Да, это определенно одна из причин использовать его. Кроме того, фрагмент документа может содержать любой тип узла, тогда как элемент не может.
Тим Даун
3
На самом деле фрагмент не «исчезает»; браузер перемещает свои дочерние узлы в DOM. Таким образом, фрагмент все еще существует, но после вставки он будет пустым.
inf3rno
1
@ inf3rno: Поэтому я использую слово «эффективно» и следующее за ним объяснение, которое во многом совпадает с вашим. Я признаю, что должен был прямо сказать в ответе, что фрагмент продолжает существовать без дочерних узлов.
Тим Даун
1
@TimDown спасибо за ответ! Если я правильно понимаю, что касается производительности, использование createFragmentи использование createElementпамяти имеет примерно такой же эффект, поскольку они оба пакетно обновляли DOM, а не итеративно обновляли несколько раз. Хотя основным преимуществом createFragmentявляется то, что он предлагает вам гибкость в выборе любых дочерних элементов для добавления бесплатно? Поправьте меня, если я ошибался.
Xlee
9

Еще одно очень важное различие между созданием элемента и фрагмента документа:

Когда вы создаете элемент и добавляете его в DOM, этот элемент добавляется к DOM вместе с дочерними элементами.

К фрагменту документа добавляются только дочерние элементы.

Возьмем случай:

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>

что приводит к этому искаженному HTML (добавлен пробел)

<ul id="ul_test">
  <li>Document Fragment</li>
  <div><li>Inside Div</li></div>
</ul>
Джереми Дж. Старчер
источник