本条情势以jQuery源码中相比较靠后的地方出现,重要用来两地处。1凡布局jQuery对象的下以 2.是也DOM操作提供底层协理,这为便是胡先读书她的缘由。此前的随笔已经分析过jQuery的构造函数了,也波及了出12只支行,其中起一个子就经jQuery.buildFragment方法来处理的,什么意况呢?就是在拍卖千头万绪html标签的上,例如$(‘<div>123</div>’)这样的款型,在构造函数内部通过ret变量判断是无是粗略标签,如要是就是调用js的createElement方法直接创建元素如无是啊就由此者模式处理有关讲解可以参见字符串情形分类分析。本文重假若座谈是形式以协会jQuery对象上的功用。

打听文档片段documentFragment

Javascript中生documentFragment方法用于创制文档片段,什么是文档片段吧?就是创造出来的素表示文档的同等部分可可不属文档树。可以简简单单的知晓啊缓存的文档元素,通常我们会动用她来成立文档元素,我们能够文档片段的性状先将要插入的文档创建于文档片段中然后总体插入,相对于一个一个底插入文档元素而言性能会增强广大。那里引用一个例:

 

//假如想创建十个段落,使用常规的方式可能会写出这样的代码:
var i = 0 ; i < 10; i ++) {
    var p = document.createElement("p");
    var oTxt = document.createTextNode("段落" + i);
    p.appendChild(oTxt);
    document.body.appendChild(p);
}
当然,这段代码运行是没有问题,但是他调用了十次document.body.appendChild(),每次都要产生一次页面渲染。这时碎片就十分有用了:

var oFragment = document.createDocumentFragment();

for(var i = 0 ; i < 10; i ++) {
    var p = document.createElement("p");
    var oTxt = document.createTextNode("段落" + i);
    p.appendChild(oTxt);
    oFragment.appendChild(p);<br>}
    document.body.appendChild(oFragment);

 

在这段代码中,每个新的<p />元素都被添加到文档碎片中,然后这个碎片被作为参数传递给appendChild()。这里对appendChild()的调用实际上并不是把文档碎片本省追加到body元素中,而是仅仅追加碎片中的子节点,然后可以看到明显的性能提升,document.body.appenChild()一次替代十次,这意味着只需要进行一个内容渲染刷新。

兑现原理

jQuery.buildFragment方法会首先成立一个文档片段,然后于调用jQuery.clean方法以结果转换为dom元素,其中为更好了提升效能,jQuery在斯措施被在了缓存机制,假若符合缓存会在读取时亲切从缓存读取设置的时节呢会发一个缓存备份供下一破接纳。

源码分析

jQuery.buildFragment = function( args, nodes, scripts ) {
    var fragment, cacheable, cacheresults, doc,

    first = args[ 0 ];

   ...
}

首先会合接受3只参数args表示的需要变为DOM元素的HTML代码它是一个数组;nodes也是一个数组用于修正创设文档片段的的文档对象;script是存script元素的这重要跟dom操作暴发提到。这样看或者当没什么概念这个参数何地来的?那么就招来找前调用方法的地点:

} else {
          ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
          selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
 }

在认清不是简单标签的时节就是管[ match[1]
], [ doc
]以此简单只东西传递了进来,现在了解怎么前片个参数仍然数组了第一单数组是出色到之标签第二只数组是文档对象为起或是jquery对象要dom元素不妨调用一下望那些参数的值更清一点:

在html里面创制jquery对象

 <script>
       $('<div><124/div>')
   </script>

  然后又jQuery源码中查看参数

} else {
   console.log(match[1]);
    console.log(doc);
    ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
    selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
}

以浏览器中运作的结果

<div><124/div>
#document<!DOCTYPE html><html>​…​</html>​

jQuery,还更换一个特有一点底

  $('<div><124/div>',{'class':'test'});

当浏览器被运作的结果

<div><124/div>
jquery-1.7.1.js:157 Object {class: "test"}

这些时的doc就是见惯不惊对象啊,至于第两个参数是以domManip方法吃传递的凡操作DOM的主意先不任。

继之注脚了5单变量,fragment指为稍后可能创设的文档片段DocumentFragment;cacheable表示是否满意缓存条件,唯有满意的才会拓展缓存操作;cacheresults是起缓存对象读取的文档片段包含了缓存的DOM元素;变量doc表示成立文档片段的文档对象;first取得是累累组的率先单要素以也闹或创立六只元素比如$(‘<div>123</div>,<a>123</a>’)。接着看源码:

// nodes may contain either an explicit document object,
    // a jQuery collection or context object.
    // If nodes[0] contains a valid object to assign to doc
    if ( nodes && nodes[0] ) {
        doc = nodes[0].ownerDocument || nodes[0];
    }

眼看段代码是拍卖文档对象的,下边也剖析了了传递过来的nodes里面可能是文档对象document也闹或是平时对象呢有或是jQuery对象或DOM元素

万一nodes存在以不是空的讲话先品尝取它的ownerDocument把他赋值给doc,说白了便是事先修正DOM元素的状。

    // Ensure that an attr object doesn't incorrectly stand in as a document object
    // Chrome and Firefox seem to allow this to occur and will throw exception
    // Fixes #8950
    if ( !doc.createDocumentFragment ) {
        doc = document;
    }

doc就是更正文档对象的,显明达到一个法不顶给力只处理了DOM元素的情状,紧接着就同段落就是是拍卖不是DOM元素的场地,假若不有createDocumentFragment的办法求证不是DOM元素就是径直为doc等于document,这里doc修正了会尽是创立文档片段的文档对象。

    // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
    // Cloning options loses the selected state, so don't cache them
    // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
    // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
    // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
    if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
        first.charAt(0) === "<" && !rnocache.test( first ) &&
        (jQuery.support.checkClone || !rchecked.test( first )) &&
        (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
        cacheable = true;
        cacheresults = jQuery.fragments[ first ];
        if ( cacheresults && cacheresults !== 1 ) {
            fragment = cacheresults;
        }
    }

即时同一段落是拍卖缓存的底,首先使一口咬定一下凡是匪是入缓存条件里囊括了

 1、数组 args 的长短也
1,且第一个要素是字符串,即数组 args 中特包含一段 HTML代码。
‰ 2、 HTML 代码的长度小于 512(1/2KB)
,否则恐怕相会造成缓存占用的内存过非常。
 3、‰ ‰ 文档对象 doc
是当下文档对象,即只有缓存为当下文档制造的 DOM
元素,不缓存其他框架(iframe)的。
 4、‰ ‰ HTML 代码以错误尖括号先导,即只有缓存
DOM 元素,不缓存文本节点。
‰ 5、 HTML
代码中无克含有以下标签:<script>、<object>、<embed>、<option>、<style>。
‰ 6、
当前浏览器可正确地复制单选按钮和复选框的当选状态 checked,或者 HTML
代码中的单选按钮和复选按钮无吃入选。
 7、‰ ‰ 当前浏览器可是地复制 HTML5
元素,或者 HTML 代码中不带有 HTML5 标签

后两个条件用到了jquery的效能检测与正则紧假如判这个原则,一旦那么些原则满足就管cacheable属性改成为true表示入缓存条件。

接下来尝试在由jQuery.fragments对象被读取缓存结果,倘诺前已成立了dom元素了在jQuery.fragments对象吃暴发结果这尽管径直调缓存结果jQuery.fragments
方法以jQuery.buildFragment方法之后注解用于保存缓存的文档片段默看空。

假若cacheresults有价而且未呢1不怕调缓存结果,把结果赋值给fragment,为何而认清为1为?看到后头就是知道了。

jQuery.fragments = {};

随着看源码:

    if ( !fragment ) {
        fragment = doc.createDocumentFragment();
        jQuery.clean( args, doc, fragment, scripts );
    }

fragment没有值说明没有缓存结果那就自己创建文档片段交给fragment然后调用clean方法转成dom元素。其实最终是clean方法处理的,找个方法比较复杂下一篇再分析吧。

    if ( cacheable ) {
        jQuery.fragments[ first ] = cacheresults ? fragment : 1;
    }

    return { fragment: fragment, cacheable: cacheable };

随后朝后关禁闭,固然符合缓存条件虽管结果缓存起来保存到jQuery.fragments那多少个目的吃错过,它的结果在cacheresults是否存在,不在就是1即虽是干什么前面要判断cacheresults !==
1的由来。最后回到一个目的涵盖文档片段及是否知足缓存条件的结果其他地点还冲重临的结果举行相应的处理。

现今更来完全的禁闭一下斯点子的用法:首先当就算我们先是潮传入一个错综复杂标签创造jQuery对象时会合率先修正文档对象保证吗document,然后会判定是否满意缓存条件,然后找到存储缓存文档片段的靶子jQuery.fragments看是不是暴发价将结果就是赋值给cacheresults,cacheresults有价当将他赋值给fragment,由于是第一蹩脚利用得是无值得f
( !fragment )是啊真是时刻调用js方法fragment =
doc.createDocumentFragment();创造文档片段fragment,最终用clean方法处理文档片段构造jQuery对象。假如咱们传递的参数是永葆缓存的这cacheable为真可是cacheresults又无有用jQuery.fragments[
first
]价值变成了同一。当我们第二欠好当使用同样的参数时,由于匪饱cacheresults !==
1的极所以依然会自己创设而这的cacheresults是1并非无价值是时节才拿创造好的文档片段fragment放到jQuery.fragments中,当大家第三差以同样的参数时便相会活动调用jQuery.fragments的结果啦,所以是第三浅开头才能够使缓存的。为啥jQuery要以第三破才可以调用缓存呢?完全可在首先赖就将缓存结果保存于jQuery.fragments去次潮就是可调用了,那里恐怕发任何的用我暂时还尚未感念吓。最终附上完整源码:

 1 Query.buildFragment = function( args, nodes, scripts ) {
 2     var fragment, cacheable, cacheresults, doc,
 3     first = args[ 0 ];
 4 
 5     // nodes may contain either an explicit document object,
 6     // a jQuery collection or context object.
 7     // If nodes[0] contains a valid object to assign to doc
 8     if ( nodes && nodes[0] ) {
 9         doc = nodes[0].ownerDocument || nodes[0];
10     }
11 
12     // Ensure that an attr object doesn't incorrectly stand in as a document object
13     // Chrome and Firefox seem to allow this to occur and will throw exception
14     // Fixes #8950
15     if ( !doc.createDocumentFragment ) {
16         doc = document;
17     }
18 
19     // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
20     // Cloning options loses the selected state, so don't cache them
21     // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
22     // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
23     // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
24     if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
25         first.charAt(0) === "<" && !rnocache.test( first ) &&
26         (jQuery.support.checkClone || !rchecked.test( first )) &&
27         (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
28 
29         cacheable = true;
30 
31         cacheresults = jQuery.fragments[ first ];
32         if ( cacheresults && cacheresults !== 1 ) {
33             fragment = cacheresults;
34         }
35     }
36 
37     if ( !fragment ) {
38         fragment = doc.createDocumentFragment();
39         jQuery.clean( args, doc, fragment, scripts );
40     }
41 
42     if ( cacheable ) {
43         jQuery.fragments[ first ] = cacheresults ? fragment : 1;
44     }
45 
46     return { fragment: fragment, cacheable: cacheable };
47 };
48 
49 jQuery.fragments = {};

 

 

相关文章

网站地图xml地图