• 页面优化,DocumentFragment对象详解


    一、前言

    最近项目不是很忙,所以去看了下之前总想整理的重汇和回流的相关资料,关于回流优化,提到了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是个什么东西,怎么使用它,那么本文就到这里结束了。

    参考资料

    深入理解DOM节点类型第四篇——文档片段节点DocumentFragment

    DocumentFragment对象

  • 相关阅读:
    对list集合中的对象进行排序(转载)
    关键字的作用
    CocoaPods的 安装 /卸载/升级
    block基本使用和底层
    程序启动 - 类调用的方法
    成员变量修饰词的作用
    宏(define)与常量(const)
    iOS
    监听网络状态
    nil、Nil、NULL与NSNull的区别及应用
  • 原文地址:https://www.cnblogs.com/echolun/p/10098752.html
Copyright © 2020-2023  润新知