做者 : 混元霹靂手-ziksangjavascript
不管在作項目仍是學知識,當看到DocumentFragment 這個文檔碎片的時候,你並不會去在乎他,每每就是這東西就能看的出你對Js的認識,和一個層級的化分,前天我看到一位小兄弟發了一篇文章,上面寫着阿里十道面試題,裏面有一個問題是這樣的html
3.請把<body><p>第1行</p><p>第2行</p>...</body>
(body之間有100個p元素)插入body裏面,注意:須要考慮到性能問題。前端
對於想固然的想法vue
for(var i=0;i<100;i++)
{
var op=document.createElement("p");
var oText=document.createTextNode(i);
op.appendChild(oText);
document.body.appendChild(op);
}複製代碼
咱們for大法進行循環建立一百次p無素,很顯示,每次JavaScript對DOM的操做是一個很消耗性能的問題,頁且每次進行appendchild插入節點的時候,會致使頁面進行重繪(paining),對(layout)從新佈局,那這個操做說明建立了100次節點,重繪了100次,暫且不談,很顯然,性能問題出來了。那面試的小夥是如何回答的這個問題的?java
對於這個回答,性能問題是解決了,是減小了dom的操做,若是我是面試官只給50分,那如何拿到更高的分數,其實本質上我想的是面試官確定考的不是經過這個知識點來解決此問題,我把代碼重新寫一遍jquery
var lis = "",ul = document.createElement("ul");
//把li以字符串形式生成
for(var i = 1; i <= 100; i++) { lis += "<li>第" + i + "行</li>";}// 最後經過innerHTML插入ul裏面
ul.innerHTML = lis;
//這裏才操做dom,把ul插入到body
document.body.appendChild(ul);複製代碼
此方法只進行了一次dom操做,和一次頁面重繪,是一個好辦法,可是我以爲這個方法有點硬湊的感受,沒有把dom的知識點掌握全,並且這種寫法對後續的拓展和維護性是不存在的,也沒法封裝成一個方法或者結合到任何框架中去面試
而後我想到這東西,不管是jquery仍是vue都使用了這玩意文檔碎片
來進行dom操做dom級別的優化瀏覽器
DocumentFragment
接口表示沒有父級的最小文檔對象。它被用做輕量級版本,Document以像標準文檔同樣存儲由節點組成的文檔結構的片斷。關鍵區別在於,因爲文檔片斷不是實際DOM結構的一部分,它是一個虛擬的dom節點,存在於內存中,因此對片斷所作的更改不會影響文檔,致使迴流,或者在進行更改時可能會發生任何性能影響。微信
一個常見的用途DocumentFragment
是建立一個,在其中組裝一個DOM子樹,而後使用Node諸如appendChild()或(或insertBefore())之類的接口方法將該片斷附加或插入到DOM中。這樣作會將片斷的節點移動到DOM中,留下空白DocumentFragment
。由於全部的節點都被一次性插入到文檔中,因此若是單獨插入,則每一個節點只會觸發一個迴流和渲染,而不是每一個節點的潛在一個app
建立DocumentFragment ->document.createDocumentFragment()
var oFrag=document.createDocumentFragment();
for(var i=0;i<100;i++)
{
var op=document.createElement("P");
var oText=document.createTextNode(i);
op.appendChild(oText);
oFrag.appendChild(op);
}
document.body.appendChild(oFrag);複製代碼
很明顯,它有一種特殊的行爲,該行爲使得它很是有用,即當請求把一個DocumentFragment
節點插入文檔樹時,插入的不是 DocumentFragment
自身,而是它的全部子孫節點。這使得DocumentFragment
成了有用的佔位符,暫時存放那些一次插入文檔的節點。它還有利於實現文檔的剪切、複製和粘貼操做。
此時咱們操做了兩次dom,和一次重繪,爲了建立文檔碎片咱們多操做了一次dom換來了100次dom建立的優化,並無什麼問題,也不用糾結這個問題。此時只是把documentFragment的子節點添加到了body節點裏,並無把整個文檔碎片加入進去。
當文檔碎片插入完自動會被銷燬碎片內容
var oFrag=document.createDocumentFragment();
for(var i=0;i<100;i++)
{
var op=document.createElement("P");
var oText=document.createTextNode(i);
op.appendChild(oText);
oFrag.appendChild(op);
}
document.body.appendChild(oFrag);
for(var i=0;i<100;i++)
{
var op=document.createElement("P");
var oText=document.createTextNode(i);
op.appendChild(oText);
oFrag.appendChild(op);
}
//這段代碼中
document.body.appendChild(oFrag);複製代碼
你運行代碼你會發現0-99,0-99,說明了什麼?說明了只要文檔碎片一但被插入後,會進行一個碎片回收,清除,可是文檔碎片容器仍是存在的,咱們不用再次從新再進行一次dom操做來進行建立文檔碎片
移除dom到文檔碎片中
若是將文檔中的節點添加到文檔碎片中,就會從文檔中移除該節點,也不會從瀏覽器再看到該節點,添加到文檔碎片的新節點也不屬於文檔樹
<html>
<head> <meta charset="UTF-8"> <title>v-circle</title> </head> <body> <div> <ul> <li>1</li> <li>2</li> </ul> </div> <script type="text/javascript"> var oFrag=document.createDocumentFragment(); var ul = document.getElementsByTagName('ul')[0] console.log(ul) oFrag.appendChild(ul) </script> </body> </html>複製代碼
此時我把DOM樹中的ul節點添加到文檔碎片中,此時dom樹中的ul節點也不見了,跑到了文檔碎片中
你也能夠很明顯的看的出,文檔碎片不存在於dom樹中。因此上全部的操做不會重繪整個頁面
jquery做者John Resig給了性能測試報告
雖然在2008年給出的報告,對於現代瀏覽器中,此性能差距不是很大,100次可能算不上什麼,但對於前端大數據的時代裏,仍是頗有必要的。
歡迎指正!!!!!!
想了解更多知識歡迎訂閱個人掘金專欄
渣渣前端開發工程師,喜歡鑽研,熱愛分享和講解教學請 微信 zzx1994428 QQ494755899
若是轉載請標註出自@混元霹靂手ziksang