最近在啃jQuery1.11源码,上来就遇到Sizzle这个jQuery的大核心,虽然已经清楚了Sizzle的用途,先绕过去也没事,但明知山有虎偏向虎山行才是我们要做的。

本文面向的阅读对象:正在学习Sizzle源码或有一定前端基础的同学们,可以一边看源码一边看这些文章进行验证,所以虽然我会分析源码中的正则表达式,有大量的注释,但不会讲正则表达式的基本用法!(我会给出一些链接,但不一定全面,请锻炼自主搜索的能力;为了避免歧义,本文的一些词会采用源码中的英文或js中的属性名)

Sizzle部分的代码已经啃完,本系列还有后续,这几天将会一一放出。本文主要分为两个部分:什么是SizzleSizzle的原理以及Sizzle结构概览

什么是Sizzle?

简单地来说,Sizzle是一个可以让你用CSS 选择器(selector)形式去获取DOM元素的引擎。

当我们想了解一个函数的用途和源码,必须先看它的要求和效果,就是输入和输出。

例如:你提供一个CSS selector 'html > body',Sizzle会返回给你一个数组,数组中只有一个元素body元素。

还有更复杂的CSS selector,比如 ‘body > div#main div.content input[type="text"]:nth(2)’,更多selector的用法请看

CSS selector用法

Sizzle的原理

我们先想想,如果让我们自己写一个Sizzle,先不考虑其中遇到的设计和细节问题,你会怎么做?

一个很自然的想法是,从父元素顺藤摸瓜往下一层层找下去。比如‘html > body’,我先找到nodeName为html的元素,再查看html的子元素里有没有一个nodeName为body的元素即可。

那么会面对几个问题:

你怎么知道在哪儿找html元素?于是我们需要一个查找上下文(context),默认为文档节点(document)

你怎么知道要找的是html元素而非h元素或者ht元素?所以我们需要一个词法分析器(tokenize),把selector切成三个词元(token)(一个数组(tokens)),[‘html’,'>','body']。(关于词法分析器,请学习编译原理相关知识)

难道处理‘html’和处理‘>’的方式是一样的?你怎么知道它要查找子元素?我们知道它们是不同的类型的词元(token),所以要记录词元的类型,上面的数组变为[{value:'html',type:'TAG'},{value:'>',type:'>'},{value:'body',type:'TAG'}],再交给对应的处理函数处理

难道每次我们都来上面这么一套么?我们经常用的不就是$('#id')或者$('.className')这样简单的用法么?所以我们可以把这种高频率的特殊情况拿出来先处理,处理不掉再用统一的方法处理。

上面这一套,从左往右匹配,从逻辑上来看是没什么问题的。那么思考下面这种情况

‘因为DOM是一种树形结构,所以越往下层,子节点是越多的,那么会有这样一种情况,body元素下有10000个div子元素,其中在5000的位置处有一个div的id为suprise。’这时给你一个内容为body > div#suprise的selector,你写的引擎会怎么处理?

继续用上面的方法,先找出body元素,然后一个个遍历body的子元素?

可以预见的是性能上的悲剧。。。

所以我们的Sizzle采用的是从右向左的匹配方式:

先调用getElementById('suprise')来获得该DOM元素(find过程)(因为浏览器低层目测会建立id的索引,所以获得非常快,即使需要遍历DOM树,也比我们自己遍历DOM树快),

再根据'>'判断其父元素是否是body元素(filter过程)即可。

OK,到这里为止性能方面有了一定的改进,再考虑一种情况:

'当我们需要查找的层次很深时,比如selector为body > div#main div.content input[type="text"]时,我们需要先找到待选(seed)的input,再依次过滤[type="text"]、div.content 、div#main 、body>,你们会怎么做?'

判断不同的token类型,再通过查找找到对应的过滤函数,并调用对应的过滤函数(filter),这是一个正常的想法。

那么我需要再用该selector来查找一次呢?(这是使用jQuery非常常见的场景)把上面的过滤过程再重复一遍?

于是另一种提升性能的方式出现了——缓存,把上面的多个过滤函数编译成一个匹配函数(matcher),然后以key-value的形式存在缓存里面,当我们再次查找同样的selector时,只需要把编译好的匹配函数(matcher)给取出来过滤用就可以了。

Sizzle的全部原理大致如上,至于特性检测、沙盒、bugfix这些细节,后面再说

Sizzle的结构概览

Sizzle的结构不用记,大致看看就好,后面会一一说到的,放一张图,来源:http://www.cnblogs.com/mufc-go/p/3299261.html

本文完。

剩下的下午健完身回来再发。

感谢@司徒正美(1.3版本源码分析),@nuysoft(1.7版本源码分析),@Aaron(2.03版本源码分析)给我的参考。

如果你喜欢这篇文章,请给我一个推荐,如果觉得有问题,请在评论里抽打我!

jQuery1.11源码分析(1)-----Sizzle源码概览[原创]的更多相关文章

  1. jQuery1.11源码分析(2)-----Sizzle源码中的正则表达式[原创]

    看完了上篇,对Sizzle有了一个大致的了解,我们接下来就可以正式开始啃Sizzle的源码了.上来就讲matcher难度太大,先来点开胃菜,讲讲Sizzle中的各个正则表达式的作用吧(本来还想讲初始化 ...

  2. jQuery1.11源码分析(3)-----Sizzle源码中的浏览器兼容性检测和处理[原创]

    上一章讲了正则表达式,这一章继续我们的前菜,浏览器兼容性处理. 先介绍一个简单的沙盒测试函数. /** * Support testing using an element * @param {Fun ...

  3. NIO 源码分析(05) Channel 源码分析

    目录 一.Channel 类图 二.begin 和 close 是什么 2.1 AbstractInterruptibleChannel 中的 begin 和 close 2.2 Selector 中 ...

  4. NIO 源码分析(02-2) BIO 源码分析 Socket

    目录 一.BIO 最简使用姿势 二.connect 方法 2.1 Socket.connect 方法 2.2 AbstractPlainSocketImpl.connect 方法 2.3 DualSt ...

  5. NIO 源码分析(02-1) BIO 源码分析

    目录 一.BIO 最简使用姿势 二.ServerSocket 源码分析 2.1 相关类图 2.2 主要属性 2.3 构造函数 2.4 bind 方法 2.5 accept 方法 2.6 总结 NIO ...

  6. [源码分析] 从实例和源码入手看 Flink 之广播 Broadcast

    [源码分析] 从实例和源码入手看 Flink 之广播 Broadcast 0x00 摘要 本文将通过源码分析和实例讲解,带领大家熟悉Flink的广播变量机制. 0x01 业务需求 1. 场景需求 对黑 ...

  7. drf的基本使用、APIView源码分析和CBV源码拓展

    cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...

  8. Spring Ioc源码分析系列--Ioc源码入口分析

    Spring Ioc源码分析系列--Ioc源码入口分析 本系列文章代码基于Spring Framework 5.2.x 前言 上一篇文章Spring Ioc源码分析系列--Ioc的基础知识准备介绍了I ...

  9. k8s client-go源码分析 informer源码分析(3)-Reflector源码分析

    k8s client-go源码分析 informer源码分析(3)-Reflector源码分析 1.Reflector概述 Reflector从kube-apiserver中list&watc ...

随机推荐

  1. Ubuntu安装Svn,提供http访问

    安装相关package sudo apt-get install subversion subversion-tools apache2 libapache2-svn apache2-utils 创建 ...

  2. <总结>delphi WebBrowser控件的使用中出现的bug

    Delphi WebBrowser控件的使用中出现的bug:  1.WebBrowser.Visible=false:Visible属性不能使WebBrowser控件不可见,暂时用 WebBrowse ...

  3. Entity Framework 6 with MySql

        MySQL Connector/Net 6.8.x MySQL Server 5.1 or above Entity Framework 6 assemblies .NET Framework ...

  4. 洛谷P1288 取数游戏II[博弈论]

    题目描述 有一个取数的游戏.初始时,给出一个环,环上的每条边上都有一个非负整数.这些整数中至少有一个0.然后,将一枚硬币放在环上的一个节点上.两个玩家就是以这个放硬币的节点为起点开始这个游戏,两人轮流 ...

  5. UVALive - 4108 SKYLINE[线段树]

    UVALive - 4108 SKYLINE Time Limit: 3000MS     64bit IO Format: %lld & %llu Submit Status uDebug ...

  6. 6.bootstrap练习笔记-缩略图和list-group

    bootstrap练习笔记-缩略图 1.其实缩略图很简单,只要按照固定的格式来设计 div.container 总容器  在宽度为1200px以上 div.row 一行内容 div.col-lg-3. ...

  7. Freemarker常用技巧

    1,截取字符串 有的时候我们在页面中不需要显示那么长的字符串,比如新闻标题,这样用下面的例子就可以自定义显示的长度 < lt. <= lte. > gt. >= gte < ...

  8. MODI与VB6

    作者:马健邮箱:stronghorse_mj@hotmail.com主页:http://www.comicer.com/stronghorse发布:2016.12.16 在我写的<用MODI O ...

  9. win8安装SQL Server 2005问题解决方法

    win8安装SQL Server 2005问题解决方法 1.正常安装任一版本的SQL Server 2005(最好安装企业版). 2.安装到SqlServer服务的时候提示启动服务失败(提示重试的时候 ...

  10. ModernUI教程:创建自定义主题

            Modern UI WPF包括两个内置主题(dark与light).在1.0.3版本,您可以构建自定义的主题.Modern UI应用程序通常有在全局资源字典App.xaml中有如下定义 ...