`
zha_zi
  • 浏览: 593987 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Sizzle 引擎--原理与实践1

css 
阅读更多
本文地址:http://www.cnblogs.com/xesam/archive/2012/02/15/2352466.html
 
Sizzle引擎--原理与实践(一)

  大家都知道,Sizzle是jQuery的御用选择器引擎,是jQuery作者John Resig写的DOM选择器引擎,速度号称业界第一。另外,Sizzle是独立的一部分,不依赖任何库,如果你不想用jQuery,可 以只用Sizzle。所以单独拿出来特别对待。在Prototype1.7中,选择器也采用了Sizzle,不过版本有点老,所以我去Sizzle网站搞了一份新的 下来,于是下面分析的时候使用的是最新版的Sizzle.js

预先说明

在分析初期为了保证各个浏览器的结果一致,不考虑原生getElementsByClass以及querySelectorAll的影响,同时忽略XML类型,因此作一下处理:
源码1292行,

(function(){
    ...
})()

改为:

(function(){
    return false;
    ...
})()

源码1140行

if ( document.querySelectorAll ) {
    ...
}

改为:

if ( document.querySelectorAll && false) {
    ...
}

至于其他的浏览器兼容处理部分,会在初步分析中一并涉及。

预备知识

CSS选择器jQuery选择器。由于jQuery选择器的形式来自CSS,但是在CSS的基础上又增加了很多新的选择表达式,因此,一切以jQuery选择器为基础。

实例开题:

对于一个选择表达式:

div#outer > ul , div p:nth(1),form input[type="text"]

关于分块的讨论

这里面包含三个并联的选择符,我们怎么处理?
解决方案:
1、可以用split(',')来处理,但是这样只是单纯的分割出来了,并不能获得更多的信息。
2、所以我们采用正则来分块,缺点是可读性以及效率的问题,优点是可以提取一些必要的信息,进行预处理。

所以jquery采取的是正则,但是并没有完全分块,而是一部分一部分的取。对于上面的例子我们看看怎么分块。

div#outer > ul , div p:nth(1),form input[type="text"]先分离出来div#outer > ul,处理完毕后再分离出来div p:nth(1),处理完毕后再分离出来form input[type="text"],最后合并三部分的结果

关于选择顺序的讨论

这里需要记得jQuery选择器的作用

一个典型的例子:

body div p:first-child
body div p:first


这两个的含义完全不一样,如果可以用括号这么写的话,可以改成:

body div p:first-child --> body div (p:first-child)
body div p:first --> (body div p):first


first-child是用来限定p的,可以算是p的一个属性,
body div p:first是用来限定body div p结果集的,可以算是body div p结果集的一个方法。
body div p:first == (body div p).eq(0)


类似的情况还有jQuery自定义的几个位置查询表达式,所以
情况一、body div p:first

  自左向右的查询。先找到body,获得集合A,然后在集合A中查找div获得集合B,在集合B中查找p获得集合C,最后取集合C的第一个元素,得最终结果XX

情况二、body div p:first-child  

  自右向左的查询,先找到p:first-child获得集合A1,然后判断祖先元素里面是否有div获得集合B1,然后判断祖先元素里面是否有body获得集合C1,得最终结果C1

  对比上面的两个过程,相较于过程一,过程二更像是一个过滤的过程,因此,Sizzle最大的亮点是自右向左过滤。

  另外,为了提高查询效率,最重要的就是缩小查找范围和减少遍历次数。
一个典型的例子是:
div p
  情况一、先找到p,获得集合A,然后判断祖先元素里面是否有div获得集合B,得最终结果B
div#a p
  #a一般只会有一个,所以情况一里面p的范围太大了,所以如果第一个选择表达式里面含有id,Sizzle总是先查找第一个,从而缩小查找范围
  情况二、先找到div#a,获得单个元素A1,然后再A1的环境中查找p,得最终结果B1

因此,最终的过程就变成

第一、分割表达式
第二、查找元素
第三、过滤元素(过滤分两种,1、通过元素自身属性过滤 2、通过元素之间关系过滤。)

因此可以获得Sizzle的大致代码结构:
Sizzle引擎基本结构
主要流程:window.Sizzle = function(){};
查找元素:Sizzle.find = function(){};
过滤元素:Sizzle.filter = function(){};

定义用到的一些查找方式和过滤条件:Sizzle.selectors = {};
Sizzle.selectors经常要用到,于是给它一个简短的名字,就叫做Expr

于是Sizzle的代码框架如下:

复制代码
window.Sizzle = function(){
    //主要负责分块和主线流程,通过元素之间关系过滤也被放在这个部分
};
Sizzle.find = function(){
    //查找元素
};
Sizzle.filter = function(){
    //过滤元素,主要处理通过元素自身属性过滤
};
Sizzle.selectors = {
    //命名空间,以及定义一些变量和特异方法
};
var Expr = Sizzle.selectors;//别称
复制代码

剩下的问题就是怎么获得我们需要的元素集合

 

关于查找元素的初步讨论

我们先看,怎么找元素,浏览器原生只有三种查找元素的方式
(文章开头我们已经假设初步所有的浏览器原生都不支持getElementsByClassName,虽然大部分都支持):
getElementById、getElementsByName以及getElementsByTagName。

问题一:
当我们遇到一个选择表达式的时候,怎么判断这个选择表达式是什么类型的。
解决方案:
  依次检测这个表达式的类型,获得匹配的类型,注意,一旦获得了匹配的类型,就不会继续匹配了。
  至于先匹配哪个类型,查找原则就是尽可能的缩小检索范围(特异性越高,检索范围就越小)。一般情况下,ID数量小于NAME数量,NAME数量又小于TAG数量。因此判断顺序就是['ID','NAME','TAG']
实例说明:
1、input[name="test"],先查找[name="test"],此时虽然还可以继续查找input,但是没有那个必要了,因为如果查询input之后再去取交集,会破坏程序的结构。
Sizzle的处理方式就是:先查找[name="test"]获得集合A,然后在A中过滤input,input被作为一个过滤条件丢到过滤部分去处理。

2、input#demo[name="test"] 由于ID的优先级比NAME高,所以先查找#demo获得集合A,然后在A中过滤input[name="test"],input[name="test"]被作为一个过滤条件丢到过滤部分去处理。

关于过滤元素的初步讨论

过滤是一个条件一个条件来进行的,对于一个集合A以及过滤表达式

expr='[class="test"][rel=1]:first-child'

在A中过滤[class="test"]得到集合B,此时过滤表达式expr='[rel=1]:first-child'
在B中过滤[rel=1]得到集合C,此时过滤表达式expr=':first-child'
在C中过滤:first-child得到集合D,此时过滤表达式expr='',过滤完毕

【说明,上面的顺序不代表真实的顺序,是指为了说明“过滤是一个条件一个条件来进行的”这句活而已】
过滤分两步:
第一、预过滤Expr.preFilter,处理兼容问题以及格式转换,决定下一步的走向
第一、最终过滤Expr.filter,这一步的形式都是一样的,最终返回的都是一个布尔值。

过滤方式:

假设第一轮的筛选集合:A = ['#1','#2','#3','#4','#5','#6']
过滤条件为isMatch
满足条件的集合为C = ['#1','#2','#3']

第一、

复制代码
var B = [];
for( i = 0; (item = A[i]) != null; i++ ){
    A[i] = isMatch(item);
}
for( i = 0;  i < A.length; i++ ){
    if(A[i]){
        B.push(A[i]);
    }
}
复制代码

1、['#1','#2','#3','#4','#5','#6']
2、['#1','#2','#3',false,false,false]
3、['#1','#2','#3']

第二、

var B = [];
for( i = 0; (item = A[i]) != null; i++ ){
    if(isMatch(item)){
        B.push(A[i]);
    }
}

 

分享到:
评论

相关推荐

    jQuery中的Sizzle引擎分析demo

    在这个"jQuery中的Sizzle引擎分析demo"中,我们将深入探讨Sizzle的工作原理以及如何通过实例来理解它。 Sizzle引擎的设计目标是提供一个高性能的选择器解析和执行环境,它独立于jQuery之外,可以单独使用。Sizzle...

    jQuery内核详解与实践_1.pdf

    ### jQuery内核详解与实践 #### 一、引言 jQuery作为一款流行的JavaScript库,在前端开发领域具有举足轻重的地位。它简化了许多常见的JavaScript任务,如选择元素、动画、事件处理等,使得开发者能够更加高效地...

    前端项目-epitome.zip

    - 该框架的核心特性包括:选择器引擎(Sizzle)、类系统、对象继承、事件处理、动画效果、Ajax通信、JSON解析等。 - MVP框架选择MooTools作为基础,是因为它提供了构建复杂前端应用所需的基础设施。 2. **MVP模式...

    jQuery-, jQuery源码解读 -- jQuery v1.10.2.zip

    Sizzle支持CSS1-CSS3的选择器,并能有效地匹配和选取DOM元素。通过阅读源码,我们可以学习到如何编写高效的选择器,以及如何利用Sizzle实现复杂的DOM遍历。 3. **DOM操作** jQuery提供了丰富的DOM操作方法,如`$...

    jQuery1.9中文和英文CHM手册

    3. **选择器引擎Sizzle** - jQuery 1.9继续使用Sizzle作为其选择器引擎,能高效地选取DOM元素,支持CSS1至CSS3的选择器语法。 4. **DOM操作** - 包括`.append()`, `.prepend()`, `.before()`, `.after()`, `.remove...

    jQuery表单选择器源码

    学习资源与实践 要深入理解jQuery表单选择器的源码,可以阅读`jQuery源码`和`Sizzle源码`,同时结合实际项目进行实践。`第7章 表单选择器.pdf`文档可能是对这部分内容的一个详细讲解,建议配合源码阅读,加深理解...

    妙味课堂--jQuery源码

    其核心功能是提供一个高效的DOM操作接口,这主要得益于Sizzle选择器引擎的运用,使得jQuery能够快速准确地找到页面中的元素。 2. **选择器引擎Sizzle** Sizzle是一个独立于jQuery的选择器库,支持CSS1至CSS3的选择...

    novice to ninja jquery source code

    1. **选择器引擎Sizzle**:jQuery选择器是其强大功能的关键,它基于Sizzle引擎,能处理CSS1至CSS3的选择器。Sizzle引擎的高效解析和匹配算法是理解和优化jQuery性能的重要一环。 2. **DOM操作**:jQuery提供了丰富...

    jqery源码逐步解析视频(高清)

    - **Sizzle选择器引擎**:jQuery内部使用的选择器引擎,它独立于jQuery核心之外,可以单独使用。 - **选择器解析过程**:从左到右逐个解析选择器中的每个元素,通过递归算法实现高效查找。 - **优化技巧**:利用缓存...

    jquery权威指南

    - **核心函数实现**:深入理解如选择器引擎Sizzle的工作原理,以及动画实现的细节。 通过阅读《jQuery权威指南》,读者将能够熟练运用jQuery进行高效的前端开发,并对jQuery的内部机制有深入的理解,提升Web开发...

    Packt - jQuery 1.4 Reference Guide (January 2010) (ATTiCA)

    1. **CSS选择器引擎的改进**:jQuery 1.4中的Sizzle CSS选择器引擎得到了进一步的优化,提高了DOM查询的速度和效率。 2. **新的动画效果**:新增了更多的动画选项,如`slideToggle()`、`animate()`等,使得页面元素...

    jquery基础入门

    随着对jQuery的深入,可以学习更高级的主题,如性能优化、插件开发、使用Sizzle选择器引擎等,进一步提升技能水平。 总结,jQuery是前端开发中强大的工具,通过学习其API和基本概念,可以大大提高开发效率,实现...

    JQuery1.4 文档及源码

    - **源码结构**: `jquery-1.4.4.js` 是 jQuery 1.4.4 版本的源码文件,它由多个核心模块组成,如选择器引擎(Sizzle)、事件处理、动画效果、Ajax 请求等。 - **选择器实现**: jQuery 1.4 使用 Sizzle 作为其选择...

    jquery-source-code-analysis:这是学习jquery源代码的记录-jquery source code

    jQuery的源码分析有助于开发者深入理解JavaScript的工作原理,提升JavaScript编程技能。 jQuery的源码主要分为几个部分: 1. **核心功能**: - `$` 函数是jQuery的核心,它是构造函数,接受一个DOM元素、HTML字符...

    JQuery王兴魁源码

    5. **选择器引擎Sizzle**:jQuery选择器的强大功能源于其内置的选择器引擎Sizzle,学习Sizzle的工作原理能帮助我们更好地利用jQuery选择器。 6. **API设计**:研究源码可以让我们理解jQuery是如何设计其API的,这对...

    锋利的jQuery源码

    1. **选择器引擎(Sizzle)**:jQuery选择器是其强大功能的基础,它基于Sizzle引擎实现。Sizzle支持CSS1到CSS3的选择器,并且在没有浏览器内置querySelectorAll方法的情况下提供高性能的选择功能。 2. **链式调用**...

    Jqurey 源码分析

    jQuery源码的结构清晰,包括工具函数、异步处理(Deferred)、浏览器检测(Support)、数据缓存(Data)、队列管理(queue)、属性操作(Attribute)、事件处理(Event)、选择器引擎(Sizzle)、DOM遍历和操作、CSS...

    JQUERY权威指南及源代码

    - **选择器引擎Sizzle**:jQuery选择器引擎Sizzle能解析CSS选择器并高效地找到匹配的DOM元素,它的实现涉及到正则表达式、缓存机制等。 - **链式调用**:jQuery对象是链式调用的基础,每个方法返回的都是jQuery...

    prototype源码

    Sizzle 引擎在源码中的实现涉及到字符串解析、DOM 遍历等复杂逻辑,是理解浏览器与 JavaScript 交互的关键。 7. **模块化设计** Prototype 使用模块化设计,将不同功能划分为独立的模块,如 `Form`、`Ajax`、`...

Global site tag (gtag.js) - Google Analytics