我应该使用 document.createDocumentFragment 还是 document.createElement

我是 阅读有关文件碎片的资料和 DOM reflow,我想知道 document.createDocumentFragmentdocument.createElement有什么不同,因为在我将它们附加到 DOM 元素之前,它们似乎都不存在于 DOM 中。

我做了一个测试(如下) ,所有的测试花费了完全相同的时间(大约95毫秒)。我猜这可能是因为没有任何样式应用到任何元素上,所以可能没有回流。

无论如何,基于下面的例子,为什么在插入 DOM 时要使用 createDocumentFragment而不是 createElement,以及这两者之间的区别是什么。

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');
34474 次浏览

The difference is that a document fragment effectively disappears when you add it to the DOM. What happens is that all the child nodes of the document fragment are inserted at the location in the DOM where you insert the document fragment and the document fragment itself is not inserted. The fragment itself continues to exist but now has no children.

This allows you to insert multiple nodes into the DOM at the same time:

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

Another very important difference between creating an element and a document fragment:

When you create an element and append it to the DOM, the element is appended to the DOM, as well as the children.

With a document fragment, only the children are appended.

Take the case of:

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>

which results in this malformed HTML (whitespace added)

<ul id="ul_test">
<li>Document Fragment</li>
<div><li>Inside Div</li></div>
</ul>

You can think of a DocumentFragment as a virtual DOM. It's not connected to the DOM and unlike elements, it has no parent, EVER. You can then interact with the fragment as if it's a virtual document object. It's all in memory.

It's really helpful to use fragments when you have many DOM manipulations to make or style changes, because those will trigger reflows and repaints - expensive operations on the DOM that can slow the page load down.

The bonus you get with fragment is that it triggers only one reflow when the fragment is inserted into the DOM, no matter how many children it contains.

DocumentFragment is not an element or a Node. It's a stripped down Document object with a reduced set of properties and methods.

If you've ever heard of the virtual DOM with React, they are making heavy use of DocumentFragments in the ReactDOM library. That's why it's so performant.