jQuery技术内幕:深入解析jQuery架构设计与实现原理. 2.4 jQuery.buildFragment( args, nodes, scripts )

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

2.4 jQuery.buildFragment( args, nodes, scripts )

2.4.1 实现原理

方法jQuery.buildFragment( args, nodes, scripts )先创建一个文档片段DocumentFragment,然后调用方法jQuery.clean( elems, context, fragment, scripts )将HTML代码转换为DOM元素,并存储在创建的文档片段中。

文档片段DocumentFragment表示文档的一部分,但不属于文档树。当把Document

Fragment插入文档树时,插入的不是DocumentFragment自身,而是它的所有子孙节点,即可以一次向文档树中插入多个节点。当需要插入大量节点时,相比于逐个插入节点,使用ocumentFragment一次插入多个节点,性能的提升会非常明显。

此外,如果HTML代码符合缓存条件,方法jQuery.buildFragment()还会把转换后的DOM元素缓存起来,下次(实际上是第三次)转换相同的HTML代码时直接从缓存中读取,不需要重复转换。

方法jQuery.buildFragment()同时为构造jQuery对象和DOM操作提供底层支持,DOM操作将在第11章介绍和分析。

2.4.2 源码分析

方法jQuery.buildFragment( args, nodes, scripts )执行的5个关键步骤如下:

1)如果HTML代码符合缓存条件,则尝试从缓存对象jQuery.fragments中读取缓存的DOM元素。

2)创建文档片段DocumentFragment。

3)调用方法jQuery.clean( elems, context, fragment, scripts )将HTML代码转换为DOM元素,并存储在创建的文档片段中。

4)如果HTML代码符合缓存条件,则把转换后的DOM元素放入缓存对象jQuery.fragments。

5)最后返回文档片段和缓存状态{ fragment: fragment, cacheable: cacheable }。

下面来看看该方法的源码实现。

1.?定义jQuery.buildFragment( args, nodes, scripts )

相关代码如下所示:

6085 jQuery.buildFragment = function( args, nodes, scripts ) {

第6085行:定义方法jQuery.buildFragment( args, nodes, scripts ),它接受3个参数:

参数args:数组,含有待转换为DOM元素的HTML代码。

参数nodes:数组,含有文档对象、jQuery对象或DOM元素,用于修正创建文档片段DocumentFragment的文档对象。

参数scripts:数组,用于存放HTML代码中的script元素。方法jQuery.build Fragment()会把该参数传给方法jQuery.clean(),后者把HTML代码转换为DOM元素后,会提取其中的script元素并存入数组scripts。在11.2节会看到,方法.domManip

( args, table, callback )把转换后的DOM元素插入文档树后,会手动执行数组scripts中的元素。

2.?定义局部变量,修正文档对象doc

相关代码如下所示:

6086     var fragment, cacheable, cacheresults, doc,

6087     first = args[ 0 ];

6088

6089     // nodes may contain either an explicit document object,

6090     // a jQuery collection or context object.

6091     // If nodes[0] contains a valid object to assign to doc

6092     if ( nodes && nodes[0] ) {

6093         doc = nodes[0].ownerDocument || nodes[0];

6094     }

6095

6096     // Ensure that an attr object doesn't incorrectly stand in as a document object

6097     // Chrome and Firefox seem to allow this to occur and will throw exception

6098     // Fixes #8950

6099     if ( !doc.createDocumentFragment ) {

6100         doc = document;

6101     }

6102

第6086行:定义局部变量。变量fragment指向稍后可能创建的文档片段Document

Fragment;变量cacheable表示HTML代码是否符合缓存条件;变量cacheresults指向从缓存对象jQuery.fragments 中取到的文档片段,其中包含了缓存的DOM元素;变量doc表示创建文档片段的文档对象。

第6092~6101行:修正文档对象doc。数组nodes可能包含一个明确的文档对象,也可能包含jQuery对象或DOM元素,这里先尝试读取nodes[0]的属性ownerDocument并赋值给doc,ownerDocument表示DOM元素所在的文档对象。如果nodes[0].ownerDocument不存在,则假定nodes[0]为文档对象并赋值给doc;但doc依然可能不是文档对象,如果调用jQuery构造函数时第二个参数是JavaScript对象,此时doc是传入的JavaScript对象而不是文档对象,例如,执行“$('abc<div></div>',{'class':'test'} );”时,doc是{'class':'test'},此时需要检查doc.createDocumentFragment是否存在,如果不存在则修正doc为当前文档对象 document。

3.尝试从缓存对象jQuery.fragments中读取缓存的DOM元素

如果HTML代码符合缓存条件,则尝试从缓存对象jQuery.fragments中读取缓存的DOM元素,相关代码如下所示:

6103     // Only cache "small" (1/2 KB) HTML strings that are associated with the main document

6104     // Cloning options loses the selected state, so don't cache them

6105     // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment

6106     // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache

6107     // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501

6108     if ( args.length === 1 && typeof first === "string" &&

             first.length < 512 &&

             doc === document &&

6109         first.charAt(0) === "<" &&

             !rnocache.test( first ) &&

6110         (jQuery.support.checkClone || !rchecked.test( first )) &&

6111         (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {

6112

6113         cacheable = true;

6114

6115         cacheresults = jQuery.fragments[ first ];

6116         if ( cacheresults && cacheresults !== 1 ) {

6117             fragment = cacheresults;

6118         }

6119     }

6120

6133 jQuery.fragments = {};

第6108~6111:HTML代码必须满足以下所有条件,才认为符合缓存条件:

数组args的长度为1,且第一个元素是字符串,即数组args中只含有一段HTML代码。

HTML代码的长度小于512(1/2KB),否则可能会导致缓存占用的内存过大。

文档对象doc是当前文档对象,即只缓存为当前文档创建的DOM元素,不缓存其他框架(iframe)的。

HTML代码以左尖括号开头,即只缓存DOM元素,不缓存文本节点。

HTML代码中不能含有以下标签:<script>、<object>、<embed>、<option>、<style>。

当前浏览器可以正确地复制单选按钮和复选框的选中状态checked,或者HTML代码中的单选按钮和复选按钮没有被选中。

当前浏览器可以正确地复制HTML5元素,或者HTML代码中不含有HTML5标签。

HTML代码中不能含有的标签定义在正则rnocache中,该正则的定义代码如下所示:

5651     rnocache = /<(?:script|object|embed|option|style)/i,

HTML代码中的单选按钮和复选框是否被选中通过正则rchecked检测,该正则的定义代码如下所示:

5653     // checked="checked" or checked

5654     rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,

HTML代码中是否含有HTML5标签通过正则rnoshimcache检测,该正则的定义代码如下所示:

5642 var nodeNames =

"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|" +

5643         "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",

 

5652     rnoshimcache = new RegExp(“<(?:” + nodeNames + “)”, “i”),

测试项jQuery.support.checkClone指示当前浏览器是否可以正确地复制单选按钮和复选按钮的选中状态checked,请参见7.2.14节,测试项jQuery.support.html5Clone指示当前浏览器是否可以正确地复制HTML5元素,请参见7.2.12节。

第6113行:如果HTML代码满足缓存条件,则设置变量cacheable为true。这是个很重要的状态值,在使用转换后的DOM元素时,如果变量cacheable为true,则必须先复制一份再使用,否则可以直接使用。

第6115~6118行:尝试从缓存对象jQuery.fragments中读取缓存的DOM元素。如果缓存命中,并且缓存值不是1,则表示读取到的是文档片段,赋值给变量fragment,文档片段中包含了缓存的DOM元素。稍后会看到对缓存对象jQuery.fragments中缓存值的分析。

4.?转换HTML代码为DOM元素

先创建一个文档片段DocumentFragment,然后调用方法jQuery.clean( elems, context, fragment, scripts )将HTML代码转换为DOM元素,并存储在创建的文档片段中。相关代码如下所示:

6121     if ( !fragment ) {

6122         fragment = doc.createDocumentFragment();

6123         jQuery.clean( args, doc, fragment, scripts );

6124     }

6125

第6121行:如果!fragment为true,表示需要执行转换过程。!fragment为true时可能有三种情况:

HTML代码不符合缓存条件。

HTML代码符合缓存条件,但此时是第一次转换,不存在对应的缓存。

HTML代码符合缓存条件,但此时是第二次转换,对应的缓存值是1。

第6122行:调用原生方法document.createDocumentFragment()创建文档片段。

第6123行:调用方法jQuery.clean()将HTML代码转换为DOM元素,并存储在创建的文档片段中。该方法将在2.5节介绍和分析。

5.?把转换后的DOM元素放入缓存对象jQuery.fragments

如果HTML代码符合缓存条件,则把转换后的DOM元素放入缓存对象jQuery.fragments中。相关代码如下所示:

6126     if ( cacheable ) {

6127         jQuery.fragments[ first ] = cacheresults ? fragment : 1;

6128     }

6129

第6126~6128行:如果HTML 代码符合缓存条件,则在缓存对象jQuery.fragments 中对应的缓存值如表2-2所示。

表2-2 符合缓存条件的HTML代码在缓存对象jQuery.fragments中对应的缓存值

场  景         转 换 前     转 换 后

第一次转换HTML代码 不存在     1

第二次转换同样的HTML代码     1       文档片段

两次以上转换同样的HTML代码 文档片段         文档片段

 

看到这里,可以把方法jQuery.buildFragment()的用法总结为:

如果HTML代码不符合缓存条件,则总是会执行转换过程。

如果HTML代码符合缓存条件,第一次转换后设置缓存值为1,第二次转换后设置为文档片段,从第三次开始则从缓存中读取。

6.?返回文档片段和缓存状态{ fragment: fragment, cacheable: cacheable }

相关代码如下所示:

6130     return { fragment: fragment, cacheable: cacheable };

6131 };

第6130行:最后会返回一个包含了文档片段fragment和缓存状态cacheable的对象。文档片段fragment中包含了转换后的DOM元素,缓存状态cacheable则指示了如何使用这些DOM元素。

2.4.3 小结

方法jQuery.buildFragment( args, nodes, scripts )的执行过程可以总结为如图2-5所示。

目录
打赏
0
0
0
0
1408
分享
相关文章
MySQL进阶突击系列(03) MySQL架构原理solo九魂17环连问 | 给大厂面试官的一封信
本文介绍了MySQL架构原理、存储引擎和索引的相关知识点,涵盖查询和更新SQL的执行过程、MySQL各组件的作用、存储引擎的类型及特性、索引的建立和使用原则,以及二叉树、平衡二叉树和B树的区别。通过这些内容,帮助读者深入了解MySQL的工作机制,提高数据库管理和优化能力。
【AI系统】LLVM 架构设计和原理
本文介绍了LLVM的诞生背景及其与GCC的区别,重点阐述了LLVM的架构特点,包括其组件独立性、中间表示(IR)的优势及整体架构。通过Clang+LLVM的实际编译案例,展示了从C代码到可执行文件的全过程,突显了LLVM在编译器领域的创新与优势。
86 3
《docker基础篇:2.Docker安装》包括前提说明、Docker的基本组成、Docker平台架构图解(架构版)、安装步骤、阿里云镜像加速、永远的HelloWorld、底层原理
《docker基础篇:2.Docker安装》包括前提说明、Docker的基本组成、Docker平台架构图解(架构版)、安装步骤、阿里云镜像加速、永远的HelloWorld、底层原理
220 89
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
软演员-评论家算法(Soft Actor-Critic, SAC)是深度强化学习领域的重要进展,基于最大熵框架优化策略,在探索与利用之间实现动态平衡。SAC通过双Q网络设计和自适应温度参数,提升了训练稳定性和样本效率。本文详细解析了SAC的数学原理、网络架构及PyTorch实现,涵盖演员网络的动作采样与对数概率计算、评论家网络的Q值估计及其损失函数,并介绍了完整的SAC智能体实现流程。SAC在连续动作空间中表现出色,具有高样本效率和稳定的训练过程,适合实际应用场景。
72 7
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
ClickHouse 架构原理及核心特性详解
ClickHouse 是由 Yandex 开发的开源列式数据库,专为 OLAP 场景设计,支持高效的大数据分析。其核心特性包括列式存储、字段压缩、丰富的数据类型、向量化执行和分布式查询。ClickHouse 通过多种表引擎(如 MergeTree、ReplacingMergeTree、SummingMergeTree)优化了数据写入和查询性能,适用于电商数据分析、日志分析等场景。然而,它在事务处理、单条数据更新删除及内存占用方面存在不足。
44 21
Druid 架构原理及核心特性详解
Druid 是一个分布式、支持实时多维OLAP分析的列式存储数据处理系统,适用于高速实时数据读取和灵活的多维数据分析。它通过Segment、Datasource等元数据概念管理数据,并依赖Zookeeper、Hadoop和Kafka等组件实现高可用性和扩展性。Druid采用列式存储、并行计算和预计算等技术优化查询性能,支持离线和实时数据分析。尽管其存储成本较高且查询语言功能有限,但在大数据实时分析领域表现出色。
34 19
微服务架构解析:跨越传统架构的技术革命
微服务架构(Microservices Architecture)是一种软件架构风格,它将一个大型的单体应用拆分为多个小而独立的服务,每个服务都可以独立开发、部署和扩展。
328 36
微服务架构解析:跨越传统架构的技术革命
|
1天前
|
Doris 架构原理及核心特性详解
Doris 是百度内部孵化的OLAP项目,现已开源并广泛应用。它采用MPP架构、向量化执行引擎和列存储技术,提供高性能、易用性和实时数据处理能力。系统由FE(管理节点)和BE(计算与存储节点)组成,支持水平扩展和高可用性。Doris 适用于海量数据分析,尤其在电商、游戏等行业表现出色,但资源消耗较大,复杂查询优化有局限性,生态集成度有待提高。
27 15
AArch64架构调用链性能数据采集原理
本次分享的主题是AArch64架构调用链性能数据采集原理,由阿里云苏轩楠分享。主要分为五个部分: 1. 术语解释 2. Frame Pointer RegisterStack Unwind 3. Dwarf-based Stack Unwind 4. /BRBE/CSRE Stack Unwind 5. Kernel-space Stack Unwind&eBPF Unwinders
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。

推荐镜像

更多