>  기사  >  웹 프론트엔드  >  DocumentFragment的探索之旅_html/css_WEB-ITnose

DocumentFragment的探索之旅_html/css_WEB-ITnose

WBOY
WBOY원래의
2016-06-21 08:52:511059검색

document.createDocumentFragment的探索之旅

@(author: Jsaonwong) 以下是我的 个人博客 ,欢迎大家来作客并指正我文章中的错误!

前言

事实上在写这篇文章之前想了许久,究竟要写关于哪个课题的文章,因为自己更希望写一些工作相关的课题,但是总觉得自己在工作中累计的各种经验太碎片化了,并不足以用文章输出出来,待我有空时精心整理之后再与大家分享吧,这里就先说一个大家平常都不怎么用到或者没用过的东西 DocumentFragment ;

什么是DocumentFragment?

可能许多童鞋都听说过这个东西,甚至也知道怎么使用它,但是我相信大部分的童鞋应该没有真正的去了解过它,追本溯源可以说是程序员最需要的一种特性,如果只是一味知道这个东西怎么用,或者是别人说这个东西好用就盲目地使用它,那么这恐怕并不是作者的本意。

没有真正了解过DocumentFragment这个东西的可以去 w3c 了解一下,看过之后大家就会了解到这个东西其实不是什么别的东西,正是我们耳熟能详的DOM对象。

它是一个概念比较简单却又很实用的DOM对象,w3c如是说:DocumentFragment 接口表示文档的一部分(或一段)。更确切地说,它表示一个或多个邻接的 Document 节点和它们的所有子孙节点,这要怎么理解呢!其实我是这么理解的,DocumentFragment它是一个文档碎片,轻量级的文档,能够提取部分文档的树或创建一个新的文档片段。

然而w3c下一句解释让我一开始有点懵逼,这句话是这么说的:“DocumentFragment 节点不属于文档树,继承的 parentNode 属性总是 null。”这句话又要怎么理解呢?

其实在所有节点类型中,只有DocumentFragment在文档中没有对应的标记。DOM规定文档片段(documentfragment)是一种”轻量级“的文档,可以包含和控制节点,但不会像完整的文档那样占用额外资源。

而最有用的一段概念解释当为下面这一段:“即当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作,尤其是与 Range 接口一起使用时更是如此。”

DocumentFragment的作用在最后这一段文字的解释中表达的淋漓尽致,它本身是不参与任何DOM操作的,它只是一个暂时缓存准备插入到dom的节点的“容器”。

createDocumentFragment真的如想象中神奇吗?

江湖传闻,得DocumentFragment者得天下,听说使用这个api可以对DOM操作进行优化,并且性能会得到 大量 的提升,理论上来说如果情景是for循环10000次向body插入div的话,传统的使用appendChild会导致多次的回流和重绘,必然会影响页面的性能,然而事实如此吗?因此本人捧着一颗热忱的心前去试验了一把,结果却是让我大跌眼睛。

个人写的代码如下:(如果错误或不公平的地方吗敬请指正)

第一段是for循环append的代码

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">    <title>test for append's performance</title></head>  <body>      <div id="test1">    </div></body>  <script>// per p appendvar start2 = new Date()  for(var i = 0; i < 100000; i++) {      var p = document.createElement('p');    var oText=document.createTextNode("test2");  p.appendChild(oText);    document.body.appendChild(p);}var end2 = new Date()  console.log('pappend use: ' + (end2.getTime() - start2.getTime()).toString());  </script>  </html>  

第二段是for循环append进文档碎片后再append到body的代码

<!DOCTYPE html>  <html lang="en">  <head>      <meta charset="UTF-8">    <title>test createDocumentFragment's performance</title></head>  <body>      <div id="test2">    </div></body>  <script>// fregmentvar start1 = new Date();  var fragment = document.createDocumentFragment();  for(var i = 0; i < 100000; i++) {      var p = document.createElement('p');    var oText=document.createTextNode("test2");  p.appendChild(oText);    fragment.appendChild(p);}document.body.appendChild(fragment);  var end1 = new Date()  console.log('fragment use: ' + (end1.getTime() - start1.getTime()).toString());  </script>  </html>  

最后得到的数据,我各自试了10次取了10组数据,再去掉最大和最小取平均值,得到的结果是:

传统写法的平均耗时为:173.75ms

使用文档碎片的平均耗时为:169.25ms

综合两个的数据来看感觉性能上的差距并不大,难道说,DocumentFragment是浪得虚名吗?答案当然是:NONONO!

我们都知道,做性能测试,测试环境需要适应多样化五花八门的环境,在我这些代码中dom结构及其简单,而chrome浏览器的性能也是强大到不行,因此repaint和redraw的速度极快,因此在这种情况下做出的试验数据是难以让人信服的( 事实上在IE11的测试数据中传统写法的耗时甚至比使用文档碎片的耗时要更少 )。

难道说DocumentFragment仅仅只有防止因为回流和重绘的导致闪屏的作用吗?如果你这么说,我不服,DocumentFragment也不服,所以我们要再战。

那么究竟在什么情境下测试会比较科学一些呢,我沉思半晌突然灵光一闪,既然我在大繁星工作,为什么不在繁星的项目中进行测试呢,繁星整个项目的复杂度已经属于非常复杂的情景了,因此由此测试而得到性能数据是可以值得信服的。

具体的代码其实也就是上面代码块中的js代码,嵌入到了繁星主页面中,而且是window.onload之后方才执行,保证dom已经完全加载完毕;

由此在繁星主页面下测试得到数据如下:

传统写法的平均耗时为:1168.5ms

使用文档碎片的平均耗时为:686ms

噔噔噔!!果然,在我大繁星下的测试结果,传统写法与使用文档碎片的写法性能高下立判,而且两个值的比还会随着循环的次数越多,document越复杂而逐渐变大。这也证明越是复杂的页面,文档碎片的使用得到的性能提升也往往越大。

更多的数据大家可以自己动手测试一下,毕竟动了手才有发言权,现在最流行的一句话如是说,能动手尽量不BB!

那么接下来就是大家都比较关心的一个问题,这个东西的兼容性如何呢!!!让我们一起来看看

Can I use createDocumentFragment?

结果如下:( 源自 http://caniuse.com/#search=documentfragment) 综上所述:除了IE8及以下之外都支持这一API,请大家尽情使用createDocumentFragment吧,尤其是移动端更是无往不利。(PS:不过在正确的场景中使用才是正确的做法,任何api和方法都不应该被滥用,否则很有可能会弄巧成拙哦!)

这是本人第一次写博文,错误或许在所难免,如有不正确的地方欢迎指正,如果有严重错误的地方欢迎来喷!最后欢迎大家来我的博客逛一逛 http://jasonwong1991.github.io

最后的最后再说一句,下一篇将会讲关于createDocumentFragment与createElment之间的故事,敬请期待!
성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.