Tôi có nên sử dụng document.createDocumentFragment hay document.createElement


97

Tôi đang đọc về các đoạn tài liệu và chỉnh sửa lại DOM và tự hỏi sự document.createDocumentFragmentkhác nhau như thế nào document.createElementvì có vẻ như cả hai đều không tồn tại trong DOM cho đến khi tôi nối chúng vào một phần tử DOM.

Tôi đã làm một bài kiểm tra (bên dưới) và tất cả chúng đều mất cùng một khoảng thời gian (khoảng 95 mili giây). Theo phỏng đoán, điều này có thể là do không có kiểu áp dụng cho bất kỳ phần tử nào, vì vậy có thể không chỉnh lại.

Dù sao, dựa trên ví dụ bên dưới, tại sao tôi nên sử dụng createDocumentFragmentthay vì createElementkhi chèn vào DOM và có sự khác biệt giữa hai loại này.

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

Câu trả lời:


98

Sự khác biệt là một đoạn tài liệu sẽ biến mất một cách hiệu quả khi bạn thêm nó vào DOM. Điều gì xảy ra là tất cả các nút con của đoạn tài liệu được chèn vào vị trí trong DOM nơi bạn chèn đoạn tài liệu và chính đoạn tài liệu đó không được chèn. Bản thân mảnh vỡ vẫn tiếp tục tồn tại nhưng bây giờ không có con.

Điều này cho phép bạn chèn nhiều nút vào DOM cùng một lúc:

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
Cảm ơn vì sự trả lời. Bạn nói rằng nó cho phép chèn nhiều cùng một lúc nhưng tôi có thể đạt được điều đó bằng cách sử dụng doc.createElement. Điểm khác biệt duy nhất là tôi phải bọc các phần tử trong thẻ <span> trước rồi chèn <span> đó vào DOM. Đó có phải là lý do tại sao tôi nên sử dụng createDocumentFragment? Để tránh các phần tử không cần thiết được chèn vào DOM?
screenm0nkey

4
Vâng, đó chắc chắn là một lý do để sử dụng nó. Ngoài ra, một đoạn tài liệu có thể chứa bất kỳ loại nút nào trong khi một phần tử có thể không.
Tim Down

3
Trên thực tế, mảnh vỡ không "biến mất"; trình duyệt di chuyển các Mã con của nó sang DOM. Vì vậy, phân mảnh sẽ vẫn tồn tại, nhưng nó sẽ trống sau khi chèn.
inf3rno

1
@ inf3rno: Do ​​đó cách sử dụng từ "hiệu quả" của tôi và cách giải thích sau đó, cũng giống như của bạn. Tôi thừa nhận rằng lẽ ra tôi phải nói rõ ràng trong câu trả lời rằng phân đoạn tiếp tục tồn tại mà không có nút con nào.
Tim Down

1
@TimDown cảm ơn câu trả lời của bạn! Nếu tôi hiểu đúng ý của bạn, về hiệu suất, việc sử dụng createFragmentcreateElementtrong bộ nhớ có tác dụng gần giống như cả hai đều cập nhật hàng loạt DOM thay vì cập nhật lặp đi lặp lại nhiều lần. Trong khi lợi ích chính của createFragmentnó là nó cung cấp cho bạn sự linh hoạt để chọn bất kỳ phần tử con nào để thêm miễn phí? Sửa cho tôi nếu tôi sai.
Xlee

9

Một sự khác biệt rất quan trọng khác giữa việc tạo một phần tử và một đoạn tài liệu:

Khi bạn tạo một phần tử và nối nó vào DOM, phần tử đó sẽ được nối vào DOM, cũng như các phần tử con.

Với một phân đoạn tài liệu, chỉ các phần tử con được thêm vào.

Chăm sóc:

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>

dẫn đến HTML không đúng định dạng này (đã thêm khoảng trắng)

<ul id="ul_test">
  <li>Document Fragment</li>
  <div><li>Inside Div</li></div>
</ul>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.