(转载)jQuery 1.6 源码学习(二)——core.js[2]之extend&ready方法
上次分析了extend方法的实现,而紧接着extend方法后面调用了jQuery.extend()方法(core.js 359行),今天来看看究竟core.js里为jQuery对象扩展了哪些静态方法。从源文件中看,默认的jQuery方法得有500多行,很多方法通用 性很强,因此在jQuery内部也同样作被相应实例方法所包装,一口气看完还是有点累~所以一个一个来看重要的方法。
可能在jQuery初学者中接触到最重要的方法也是最常用的便是jQuery(document).ready(fn)方法了,ready方法也可以简写为$(fn),此方法用来在DOM树加载完成后但是内容(比如图片)并为加载完毕前触发(相比于javascript的load事件)相应回调函数,那这个方法是如何实现的呢?要理解此方法首先得明白DOM专有事件[注]和HTML事件的区别。HTML事件中的load事件是在页面完全加载(css,js等)后才触发(在body或者window上绑定此事件,该事件同样兼容图像元素或Image对象),而DOM的专有事件DOMContentLoaded事件则只在完整的DOM树形成后就触发,说到这里ready方法的基本原理应该差不多成型了,而jQuery不仅实现了这样一个方法,而且还允许多次调用ready方法,并将其中的函数作为一个队列来执行,如果让我来写的话,会大致是下面这个样子:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
var myQuery={},/* 我们自己的“Query” */waitList = []; /* ready函数列表 */myQuery.ready = function(wait){ if(typeof wait === "function" ){ waitList.push(wait); }else{ console.log("not a fucntion"); }};myQuery.fireReady = function(){ while(waitList.length > 0){ waitList.shift().call(this); }};document.addEventListener( "DOMContentLoaded", myQuery.fireReady, false );/* 测试 */myQuery.ready(function(){ alert("ready one!");});myQuery.ready(function(){ alert("ready two!");}); |
当然,这个代码写的那不是一般的垃圾,权当用来理解原理了,那jQuery内部实际是怎么实现的呢?而看代码之前,还有 涉及到一个更高级的东东,叫做Deferred对象,Deferred现在在jQuery中单独成为了一个模块,此对象设计地也是十分巧妙,200行的代 码看了我一下午才明白了其中七八分奥秘,惭愧啊惭愧,简单地说来,Deferred对象中包含一个函数的执行队列(可以同步,可以异步),并支持链式调 用,有点类似一个任务队列式的观察者模型,更多关于Deferred可以参见下面列出的文章[注]。 在理解ready函数的原理时,暂时只需要知道这样一点,done函数用来存储一个回调函数列表,此列表中的函数在deferred对象resolve或 者resolveWith后被调用(两者区别是后者可以传递参数和context到回调函数中去)。下面是ready函数的全部代码:
|
1
2
3
4
5
6
7
|
ready: function( fn ) { // Attach the listeners jQuery.bindReady(); // Add the callback readyList.done( fn ); return this;}, |
是不是很简单?说白了就是先绑定ready事件,然后加入回调函数到执行列表中,然后等待DOMContentLoaded 事件触发。那么bindReady事件是怎么实现的呢?我们接着来看代码(其中中文注释由我添加,并保留英文注释):
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
bindReady: function() { if ( readyList ) { return; } //_Deferred返回一个deferred对象,且该对象仅供内部使用。 readyList = jQuery._Deferred(); // IE为DOM文档添加了readyState属性,通过此属性就可以判断文档加载情况 // Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { // 之所以用timeout来异步调用静态jQuery.ready函数,是为了确保脚本能顺利准备好 // Handle it asynchronously to allow scripts the opportunity to delay ready return setTimeout( jQuery.ready, 1 ); } //以下就是兼容各浏览器的绑定事件代码了,要注意 DOMContentLoaded 是jQuery的扫尾处理代码,core.js的结尾处将定义DOMContentLoaded如何做扫尾处理, //主要内容是删除绑定的DOMContentLoaded事件代码,和调用静态jQuery.ready函数 // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); //在IE浏览器中,处理情况稍显复杂,这里暂不讨论。 // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var toplevel = false; try { toplevel = window.frameElement == null; } catch(e) {} if ( document.documentElement.doScroll &&; toplevel ) { doScrollCheck(); } }}, |
可以看到,绑定的事件在触发之后终将执行jQuery.ready这个静态方法,那么这个方法又做了些什么事呢?
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
// Handle when the DOM is readyready: function( wait ) { //当wait传递ture时 readyWait表示当前是否有需要等待ready触发的事情的状态, //即在我们绑定的函数被触发之前wait一下, //在core.js中仅由holdReady来改变其状态,hold一次,需要再调用ready一次 //直到readyWait变为0。 //当wait不为ture时(多数情况是这样), //且isReady为假(该jQuery内的全局变量用来存储当前ready状态,默认为假)时,执行下面的代码 // Either a released hold or an DOMready/load event and not yet ready if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // 下面这句依然是处理IE的“特殊问题” // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); } // Remember that the DOM is ready jQuery.isReady = true; //释放前面提到的hold过的readyWait // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } //执行已经绑定的函数 // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); //再次触发ready函数并移除该事件处理程序 // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger( "ready" ).unbind( "ready" ); } }}, |
(转载)jQuery 1.6 源码学习(二)——core.js[2]之extend&ready方法的更多相关文章
- (转载)jQuery 1.6 源码学习(一)——core.js[1]之基本架构
在网上下了一个jQuery 1.2.6的源码分析教程,看得似懂非懂,于是还是去github上下载源码,然后慢慢看源代码学习,首先来说说core.js这个核心文件吧. jQuery整体的基本架构说起来也 ...
- Dubbo源码学习(二)
@Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...
- python 协程库gevent学习--gevent源码学习(二)
在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用mon ...
- Vue源码学习二 ———— Vue原型对象包装
Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...
- 以太坊 layer2: optimism 源码学习(二) 提现原理
作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 掘金:https://juejin.im/user/1785262612681997 博客:http://www.cnblogs.com/ ...
- metamask源码学习-ui/index.js
The UI-即上图左下角metamask-ui部分,即其图形化界面 The MetaMask UI is essentially just a website that can be configu ...
- [spring源码学习]二、IOC源码——配置文件读取
一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...
- SocketServer源码学习(二)
SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过分 ...
- Thrift源码学习二——Server层
Thrift 提供了如图五种模式:TSimpleServer.TNonblockingServer.THsHaServer.TThreadPoolServer.TThreadSelectorServe ...
随机推荐
- 关于Struts、hibernate、spring三大框架详解。
struts 控制用的 hibernate 操作数据库的 spring 用解耦的 Struts . spring . Hibernate 在各层的作用 1 ) struts 负责 web 层 . Ac ...
- [bzoj3192][JLOI2013]删除物品(树状数组)
3192: [JLOI2013]删除物品 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 872 Solved: 508[Submit][Status ...
- PHP设计模式
设计模式总的分为三种,创建型模式.结构性模式.行为型模式 1.创建型模式 创建型模式为根据实际情况来创建对象,创建的模式又分为对象创建模式和类创建模式,对象创建模式会把对象创建的一部分在另一个对象中实 ...
- JS 之JSON
JSON是Javascript中的对象,其简单理解为下:
- Sublime text3 常用插件 安装
1 安装插件前的准备工作 首先确保你的Sublime Text3编辑器为官方版(非破解版),建议下载官网的便携版本(好处多多). 然后安装插件管理工具(Package Control) 1.1 打开S ...
- Android异步任务机制之AsycTask
在Android中实现异步任务机制有两种方式,Handler和AsyncTask. 本篇就说说AsyncTask的异步实现. 1.什么时候使用 AsnyncTask 在上一篇文章已经说了,主线程主要负 ...
- MAC usb启动盘制作
1.从App Store 下载OS 2.磁盘工具格式化磁盘默认即可 3. 为啥截图,因为有些是不一样的,建议使用 Tab建, 未命名则是你移动U盘命名的名称. 4.完成:所有的命令完成的话, 终 ...
- virtualbox虚拟机中的centos与macos共享文件夹
开发中需要用到linux环境,所以使用共享模式开发.通过samba服务器来实现. 环境: 虚拟机 virtualbox 虚拟系统 centos 6.6 本机 macos 192.168.1.102 ...
- CentOS下设置MySQL的root密码
CentOS刚装的MySQL一般需要重设MySQL密码,可以用以下方法重设. 方法一. Js代码 # /etc/init.d/mysqld stop # mysqld_safe --user=my ...
- android 中调用接口发送短信
android中可以通过两种方式发送短信 第一:调用系统短信接口直接发送短信:主要代码如下: //直接调用短信接口发短信 SmsManager smsManager = SmsManager.getD ...