什么是文档片段?
(MDN解释:)DocumentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的 Document 使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。
作用是什么
与document相比,最大的区别是DocumentFragment 不是真实 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能等问题。
怎么使用DocumentFragment
let fragement = document.createDocumentFragment()console.log(fragement.nodeName)//#document-fragmentconsole.log(fragement.nodeType)//11console.log(fragement.nodeValue)//nullconsole.log(fragement.parentNode)//null
通常情况下,我们使用Node.appendChild 和 Node.insertBefore 的方法,往dom元素添加元素。每个节点分别被插入到文档中,这样会发生多次重新渲染,造成页面回流的操作,则会非常消耗性能,影响用户体验。
DocumentFragment解决了什么?
使用DocumentFragment能解决直接操作DOM引发大量回流的问题,因为所有的节点会被一次插入到文档中,而这个操作仅发生一个重渲染的操作,比如我们要给ul添加五个li节点,区别就像这样:
直接操作DOM,回流五次:
let app = document.querySelector('.app')for(let i = 0;i<5;i++){let div = document.createElement('li')div.setAttribute('class','item')div.innerText = 6666app.appendChild(div)}
使用DocumentFragment一次性添加,回流一次:
let app = document.querySelector('.app')let fragement = document.createDocumentFragment()for(let i = 0;i<5;i++){let div = document.createElement('li')div.setAttribute('class','item')div.innerText = 6666fragement.appendChild(div)}app.appendChild(fragement)
总结:DocumentFragment节点不属于文档树,存在于内存中,并不在DOM中,所以将子元素插入到文档片段中时不会引起页面回流,因此使用DocumentFragment可以起到性能优化的作用。
渲染引擎中JS对文档操作不是同步。你上述的实例代码,在执行效率上几乎一样,甚至直接操作DOM效率会更高。
一般情况下,JS中对DOM的操作会在JS执行完成之后再进行layout的更新,也就是说只会一次回流,并不是文中所说的appendChild一次就重新渲染一次。
当然,如果你在for循环中进行了DOM的相应属性的查询操作,比如div.offsetWidth,那么直接操作DOM才会导致多次重新渲染。但是这牵涉到另一个概念,强制同步布局。
浏览器会缓存一些DOM和样式变动,所以少量的时候区别不大,但是大批量的时候DocumentFragment就有很大优势了,可以确保只有一次重排或重绘,但也有一些例外,offsetWidth、clientWidth、scrollWidth等属性的读操作或getComputedStyle、getBoundingClientRect、scrollTo等方法的调用是会导致浏览器立即重绘的
这些会导致立即重排,来获取最新的位置信息。
但是不会重绘,重绘是调用渲染线程。一个 task 没有完成,不会调用渲染线程。
原文