Home  >  Article  >  Web Front-end  >  DocumentFragment的探索之旅_html/css_WEB-ITnose

DocumentFragment的探索之旅_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-21 08:52:511013browse

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之间的故事,敬请期待!
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn