jQuery之documentFragment

《jQuery之documentFragment》

前言:documentFragment 在 jQuery 中的 buildFragment() 方法中总是用到,不了解它的含义话,读源码会比较困难,写文章以记之。

1、documentFragment
含义:
documentFragment 是一个轻量级的文档对象,能够提取部分文档的树或创建一个新的文档片段,换句话说有文档缓存的作用。

特征:
(1)documentFragment 节点不属于文档树,继承的 parentNode 属性总是 null。(这一点在查找祖先节点大有用处

(2)把一个 documentFragment 节点插入文档树时,插入的不是 documentFragment 自身,而是它的所有子孙节点。

这一特点与 React.Fragment 非常类似。(React.Fragment:https://www.jianshu.com/p/d4f…

这使得 documentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。

2、<document>.createDocumentFragment() 方法
作用:
一般情况下,我们向 DOM 中添加新的元素或者节点,DOM会立刻更新。
如果向DOM添加 100 个节点,那么就得更新 100 次,非常浪费浏览器资源。

解决办法就是:
我们可以创建一个文档碎片(documentFragment),documentFragment 类似于一个小的 DOM,在它上面使用 innerHTML 并在 innerHTML 上插入多个节点,速度要快于 DOM(2-10 倍),

举个例子:

<body>
<script src="jQuery.js"></script>

<button id="Button1"  onclick = "a1()">普通方式创建</button>
<button id="Button2"   onclick = "a2()">documentFragment创建</button>
<div id="test1"></div>

<div id="test2"></div>
<script type="text/javascript">
  function a1() {
    console.time("普通方式创建")
    for (let i = 0; i < 5000; i++) {
      let op = document.createElement("span");
      let oText = document.createTextNode(i);
      op.appendChild(oText);
      document.body.appendChild(op);
    }
    console.timeEnd("普通方式创建")
  }

  function a2() {
    console.time("documentFragment创建")
    let oFragmeng = document.createDocumentFragment(); //创建文档碎片
    for (let i = 0; i < 5000; i++) {
      let op = document.createElement("span");
      let oText = document.createTextNode(i);
      op.appendChild(oText);
      oFragmeng.appendChild(op);
    }
    document.body.appendChild(oFragmeng); //最后一次性添加到document中
    console.timeEnd("documentFragment创建")
  }
</script>

《jQuery之documentFragment》

我们可以看到,在 jQuery3.3.1 中的 buildFragment 方法中,运用了这一方法,来使得 $.append()$.after() 等方法更加快速高效。

  //源码4857行-4945行
  function buildFragment( arr, context, truefalse, selection ) {
    let elem,tmp, nodes = [], i = 0, l = arr.length
    // createdocumentfragment()方法创建了一虚拟的节点对象,节点对象包含所有属性和方法。
    //相当于document.createDocumentFragment()
    let fragment = context.createDocumentFragment()
    for ( ; i < l; i++ ) {
      elem = arr[ i ];
      if ( elem || elem === 0 ) {
        tmp=fragment.appendChild( context.createElement( "div" ) );
        tmp.innerHTML =jQuery.htmlPrefilter(elem)
        jQuery.merge( nodes, tmp.childNodes );
      }
    }
    // Remove wrapper from fragment
    fragment.textContent = "";
    //需要将i重置为0
    i=0
    while ( ( elem = nodes[ i++ ] ) ) {
      fragment.appendChild( elem )
    }
    return fragment;
  }

3、createElement() 和 createDocumentFragment 的区别
(1)innerHTML

  • createElement 创建的元素可以使用 innerHTML;
  • createDocumentFragment 创建的元素使用 innerHTML 不能达到修改文档内容的效果,只能作为一个属性

(2)DOM重复操作

  • createElement 创建的元素添加到文档后可以重复操作;
  • createDocumentFragment 创建的元素是一次性的,添加之后就不能操作了

因此,在 jQuery 源码的 domMainp() 方法中,运用了 createDocumentFragment 后,需要 clone 节点,来进行操作:

//源码5900行左右
if ( i !== iNoClone ) {
    /*createDocumentFragment创建的元素是一次性的,添加之后再就不能操作了,
    所以需要克隆iNoClone的多个节点*/
    node = jQuery.clone( node, true, true );
    console.log(i,iNoClone,'iNoClone5884')
    // Keep references to cloned scripts for later restoration
    if ( hasScripts ) {
    // Support: Android <=4.0 only, PhantomJS 1 only
    // push.apply(_, arraylike) throws on ancient WebKit
    jQuery.merge( scripts, getAll( node, "script" ) );
    }
}

《jQuery之documentFragment》

(完)

    原文作者:小进进
    原文地址: https://segmentfault.com/a/1190000018651473
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞