第十二课:Sizzle引擎详解
这篇博客难度太大,跟前端开发其实没什么关系,如果你想成为大牛,那就去了解下吧。如果你还不想,那可以忽略,毕竟面试官也不会问到这里来,因为他也不太懂。呵呵。
Sizzle引擎是jQuery的选择器,它大部分操作都是从右到左进行选择,特殊选择符会从左到右。用户输入$("div"),$("div p.class"),$("div [attr=val] :checked")等各种复杂的选择符,它都能选择到用户想要取到的元素节点。
Sizzle的整体结构如下:
(1)Sizzle主函数,里面包含选择符的切割,内部循环调用主查找函数,主过滤函数,最后是去重过滤。
(2)其他辅助函数,如 uniqueSort, matches ,matchesSelector。
(3)Sizzle.find主查找函数
(4)Sizzle.filter主过滤函数
(5)Sizzle.selectors 包含各种匹配用的正则,过滤用的正则,分解用的正则,预处理函数,过滤函数。
(6)根据浏览器的特征设计makeArray,sortOrder,contains等方法。
(7)根据浏览器的特征重写Sizzle.selectors中的部分查找函数,过滤函数,查找次序。
(8)若浏览器支持querySelectorAll,那么用它重写Sizzle,将原来的Sizzle作为后备方案包裹在新的Sizzle里面。
(9)其他辅助函数,如:isXML,posProcess。
Sizzle.find主查找函数和Sizzle.filter过滤函数实现原理:
对js原生的4大查找函数,getElementById(针对id),getElementsByName(针对name),getElementsByTagName(针对标签名tagName,比如div,p),getElementsByClassName(针对class),进行一层封装,浏览器支持的话,就返回数组或者NodeList,不支持的,就返回undefined。
这里需要讲一下种子集,
种子集就是通过最右边的选择器组得到的元素集合。比如:"div.aaa span.bbb",最右边的选择器组就是"span.bbb",这时引擎会根据浏览器的支持情况选择getElementsByTagName(span)或getElementsByClassName(bbb)得到一组元素,然后再通过class(bbb)或tagName(span)进行过滤,这时得到的集合就是种子集。种子集是分两步筛选出来的,首先,通过Sizzle.find得到一个大体的结果,然后通过Sizzle.filter过滤。那我们是先取span,还是.bbb呢?这里有一个准则,要确保我们后面的映射集(当我们取得种子集后,会将种子集复制一份,这就是映射集)最小。为了达到此目的,这里有一个优化,原生选择器的调用顺序被放在一个Sizzle.selectors.order的数组中,对于低版本浏览器,其顺序为id,name,tagName,对于支持getElementsByClassName的浏览器,顺序为id,class,name,tagName。因为id只返回一个元素,class与样式相关,不是每个元素都有这个类名的,name属性使用到的几率比较少,而tagName排除的元素比较少。所以Sizzle.find就会根据Sizzle.selectors.order数组,依次调用正则,从最右的选择器中切下需要的部分,找到粗糙的节点集合。(针对"span.bbb",id调用正则时,找不到,然后class,调用正则,找到.bbb,因此就调用getElementsByClassName(bbb)得到一组数据,最后通过Sizzle.filter过滤取到的数据,过滤条件是tagName(span))
映射集,
当我们取得种子集后,会将种子集复制一份,这就是映射集。种子集是由一个选择器组选出来的,这时如果选择符不为空(前面是"div.aaa"),必然往左就是关系选择器(父亲,兄弟,后代),关系选择器会让引擎去选取其兄长或父亲,把这些元素置换到映射集对等的位置上(个数不变,因此映射集和种子集的数量总是相当)。然后到下一个选择器组时("div.aaa"),就是过滤操作了。主过滤函数Sizzle.filter会调用Sizzle.selectors下的N个过滤函数对这些元素进行检测,将不符合的元素替换为false。因此到最后要去重排时,映射集是一个包含布尔值与元素节点的数组。
下面就是根据浏览器的特征进行优化:
IE6,7下getElementById有bug。需要重写。
IE6-IE8下,Array.prototype.slice.call无法切割NodeList。需要重写makeArray。jQuery中直接用循环,把类数组转化成数组。
IE6-IE8下,getElementsByTagName("*"),会混杂注释节点。
这里大家可能会提出现在有些浏览器支持querySelectorAll方法,这是原生的,可以用来选择元素。
在Sizzle中,当浏览器支持querySelectorAll方法时,会重写Sizzle。但是在重写时,会根据不同情况提出各种提速方案:
(1)getElementById还是比querySelectorAll速度快,因为getElementById只返回一个元素,而且内部做了缓存,但是querySelectorAll会返回拥有这个id值的多个元素,尽管页面id一般是唯一的,但如果出现了多个同样id的情况下,getElementById还是只返回一个元素,而querySelectorAll会返回多个。
(2)getElementsByTagName内部也使用了缓存,而且返回的是NodeList对象,querySelectorAll返回的是一个StaticNodeList对象,前面是动态的,后面是静态的。区别在于:document.getElementsByTagName("div") == document.getElementsByTagName("div"),返回真,document.querySelectorAll("div") == document.querySelectorAll("div"),返回false.返回true的,意味着它们拿到的同是cache引用。返回false意味着每次返回都是不一样的object。数据表明:创建一个动态的NodeList对象比创建一个静态的StaticNodeList对象快90%.
加油!
第十二课:Sizzle引擎详解的更多相关文章
- 面渣逆袭:Redis连环五十二问,图文详解,这下面试稳了!
大家好,我是老三,面渣逆袭系列继续,这节我们来搞定Redis--不会有人假期玩去了吧?不会吧? 基础 1.说说什么是Redis? Redis是一种基于键值对(key-value)的NoSQL数据库. ...
- MP实战系列(十二)之封装方法详解(续二)
继续MP实战系列(十一)之封装方法详解(续一)这篇文章之后. 此次要讲的是关于查询. 查询是用的比较多的,查询很重要,好的查询,加上索引如鱼得水,不好的查询加再多索引也是无济于事. 1.selectB ...
- 第三十五课:Ajax详解
一个完整的Ajax请求: var xhr = new (self.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP"); ...
- 第三十九课:requestAnimationFrame详解
大家应该都知道,如果一个页面运行的定时器很多,无论你怎么优化,最后肯定会超过指定时间才能完成动画.定时器越多,延时越严重. 为此,YUI,kissy等采用中央队列的方式,将定时器减少至一个.浏览器厂商 ...
- Maven(十二)Maven 依赖详解
依赖的传递性 注意1:在Eclipise创建的Maven项目,若依赖eclipse空间中其他自己创建的 的项目时,此时并不会报错,但是当执行mvn compile命令时还是会显示缺失败.所以依赖的其他 ...
- PHP7 学习笔记(十二)Stream 函数详解
官方:http://php.net/manual/zh/ref.stream.php Stream_*系列函数 PHP中对流的描述如下:每一种流都实现了一个包装器(wrapper),包装器包含一些额外 ...
- Redis 学习笔记(十二)Redis 复制功能详解 ----- (error) READONLY You can't write against a read only slave
Redis 复制(Replication)1. 复制介绍分布式数据库为了获取更大的存储容量和更高的并发访问量,会将原来集中式数据库中的数据分散存储到多个通过网络连接的数据存储节点上.Redis为了解决 ...
- Vue.js 源码分析(十二) 基础篇 组件详解
组件是可复用的Vue实例,一个组件本质上是一个拥有预定义选项的一个Vue实例,组件和组件之间通过一些属性进行联系. 组件有两种注册方式,分别是全局注册和局部注册,前者通过Vue.component() ...
- Velocity魔法堂系列二:VTL语法详解
一.前言 Velocity作为历史悠久的模板引擎不单单可以替代JSP作为Java Web的服务端网页模板引擎,而且可以作为普通文本的模板引擎来增强服务端程序文本处理能力.而且Velocity被移植到不 ...
随机推荐
- ruby中 Win32ole的各应用操作方法(word excel Outlook IE)
Win32ole为标准Ruby发行版的一部分.Win32ole是访问Windows自动化的接口,可以让Ruby和Windows应用进行交互.具体说来Win32ole可以操作Word,Excel,IE, ...
- 基于Three.js的360X180度全景图预览插件
基于Three.js的360X180度全景图预览插件 时间 2015-08-12 10:01:10 HTML5中国 原文 http://www.html5cn.org/article-8621-1 ...
- APS-C画幅与全画幅
本次对比将通过视角.景深.暗角.细节等几个方面来展现APS-C画幅与全画幅的差别.希望这篇帖子中的一些说明,能对一些纠结在APS-C画幅 与全画幅之间的朋友有所帮助与参考. 同等焦距下APS-C画幅与 ...
- 一个github账户多台电脑代码提交
在实际工作生活中,我们可能不一定仅仅在一台电脑上编码,比如:我们平时在单位电脑1上写代码,提交代码到github账户,而我们也可能会在在家里的电脑2上继续工作,提交代码,这样就是在不同的电脑上提交代码 ...
- 用ADO.NET存入数据库
点击按钮存入登录名和密码: const string connstr = @"data source=USER-20160705UW\JSQL;initial catalog=Test;in ...
- 彻底搞定char/wchar_t/unicode
彻底搞定char/wchar_t!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! (2013-07-17 10:18:28) 转载▼ 从char/wchar_t到TCHAR(1) ...
- CRM Setstate plugin
pre 事件 throw new InvalidPluginExecutionException("pre-StateCode:" + StateCode + ",pre ...
- 几大最短路径算法比较(Floyd & Dijkstra & Bellman-Ford & SPFA)
几个最短路径算法的比较:Floyd 求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3). Floyd-Warshall算法(Floyd ...
- Google App Engine, Python2.7的UnicodeDecodeError bug
在跟Web Development,要在Google App Engine上写作业,出师不利,遇到以下bug: 2014-05-06 16:14:17 Running command: "[ ...
- IP地址
if (!/^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/.test($.trim($('#add ...