一、前言
最近項目不是很忙,所以去看了下之前總想整理的重匯和回流的相關資料,關於回流優化,提到了DocumentFragment的使用,這個對象在3年前我記得是有看過的,但是一直沒深入了解過,所以這里做個整理。后面會把重匯,回流也做個整理,不鴿。
二、DocumentFragment對象是什么?
MDN解釋:
DocumentFragment 表示一個沒有父級文件的最小文檔對象。它被當做一個輕量版的 Document 使用,用於存儲已排好版的或尚未打理好格式的XML片段。最大的區別是因為DocumentFragment不是真實DOM樹的一部分,它的變化不會引起DOM樹的重新渲染的操作(reflow) ,且不會導致性能等問題。---MDN
W3C解釋:
DocumentFragment 接口表示文檔的一部分(或一段)。更確切地說,它表示一個或多個鄰接的 Document 節點和它們的所有子孫節點。 DocumentFragment 節點不屬於文檔樹,繼承的 parentNode 屬性總是 null。 不過它有一種特殊的行為,該行為使得它非常有用,即當請求把一個 DocumentFragment 節點插入文檔樹時,插入的不是 DocumentFragment 自身,而是它的所有子孫節點。這使得 DocumentFragment 成了有用的占位符,暫時存放那些一次插入文檔的節點。它還有利於實現文檔的剪切、復制和粘貼操作,尤其是與 Range 接口一起使用時更是如此。 可以用 Document.createDocumentFragment() 方法創建新的空 DocumentFragment 節點。---W3C
怎么去理解呢?我們結合上面兩解釋可以得知,DocumentFragment 節點不屬於DOM樹,因此它的變化不會引起DOM樹的變化;
我們知道,DOM樹的操作會引起回流,那我們可以將DocumentFragment作為一個暫時的DOM節點存儲器,當我們在DocumentFragment 修改完成時,我們就可以將存儲DOM節點的DocumentFragment一次性加入DOM樹,從而減少回流次數,達到性能優化的目的。
三、DocumentFragment對象怎么用?
我們可以使用document.createDocumentFragment()創建一個DocumentFragment,每個新建的DocumentFragment都會繼承所有node方法。且DocumentFragment擁有nodeValue,nodeName,nodeType屬性。
let fragment = document.createDocumentFragment(); console.log(fragment.nodeValue); //null console.log(fragment.nodeName); //#document-fragment console.log(fragment.nodeType); //11
使用DocumentFragment能解決直接操作DOM引發大量回流的問題,比如我們要給ul添加五個li節點,區別就像這樣:
直接操作DOM,回流五次:
使用DocumentFragment一次性添加,回流一次:
假設我們給ul加入五萬個li,分別對比下渲染完成時間:
html: <body> <ul id="list"></ul> <ul id="list1"></ul> </body> js: //使用documentFragment添加節點 console.time("time") let list = document.querySelector("#list"), fragment = document.createDocumentFragment(), n = 50000; while(n--){ fragment.appendChild(document.createElement("li")); }; list.appendChild(fragment); console.timeEnd("time") //直接操作DOM添加節點 console.time("time1") let list1 = document.querySelector("#list1"), i = 50000; while(i--){ list1.appendChild(document.createElement("li")) }; console.timeEnd("time1")
多刷新幾次對比兩者的耗時,time是使用了DocumentFragment的耗時,time1是直接添加DOM的耗時
很明顯,time比time1耗時要短很多。
再刷新幾次試試
很明顯,多次刷新反而還會出現使用DocumentFragment耗時更久的情況,性能更差?打臉了。暫時無法解釋,希望有大佬能說說。
不過讀到這,也明白了DocumentFragment是個什么東西,怎么使用它,那么本文就到這里結束了。
參考資料