上次分析了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 ready
ready: 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方法的更多相关文章

  1. (转载)jQuery 1.6 源码学习(一)——core.js[1]之基本架构

    在网上下了一个jQuery 1.2.6的源码分析教程,看得似懂非懂,于是还是去github上下载源码,然后慢慢看源代码学习,首先来说说core.js这个核心文件吧. jQuery整体的基本架构说起来也 ...

  2. Dubbo源码学习(二)

    @Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...

  3. python 协程库gevent学习--gevent源码学习(二)

    在进行gevent源码学习一分析之后,我还对两个比较核心的问题抱有疑问: 1. gevent.Greenlet.join()以及他的list版本joinall()的原理和使用. 2. 关于在使用mon ...

  4. Vue源码学习二 ———— Vue原型对象包装

    Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...

  5. 以太坊 layer2: optimism 源码学习(二) 提现原理

    作者:林冠宏 / 指尖下的幽灵.转载者,请: 务必标明出处. 掘金:https://juejin.im/user/1785262612681997 博客:http://www.cnblogs.com/ ...

  6. metamask源码学习-ui/index.js

    The UI-即上图左下角metamask-ui部分,即其图形化界面 The MetaMask UI is essentially just a website that can be configu ...

  7. [spring源码学习]二、IOC源码——配置文件读取

    一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public cl ...

  8. SocketServer源码学习(二)

    SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过分 ...

  9. Thrift源码学习二——Server层

    Thrift 提供了如图五种模式:TSimpleServer.TNonblockingServer.THsHaServer.TThreadPoolServer.TThreadSelectorServe ...

随机推荐

  1. 第一、初识C语言

    1·C语言强大而灵活,如python,LISP,FORTRAN,Perl,Logo,BASIC,PASACAL的编译器和解释器都是C语言编写的. 2·C语言的指针错误往往难以察觉,但这恰好告诉我们,一 ...

  2. shutdown的简单小应用

    关于shutdown的操作命令在此不做详细叙述 1.WIN+R ,输入cmd即打开cmd命令界面 2.输入shutdown /help,出现下图 这里介绍一个关于shutdown的小应用: 比如我们的 ...

  3. EasyUI、Struts2、Hibernate、spring 框架整合

    经历了四个月的学习,中间过程曲折离奇,好在坚持下来了,也到了最后框架的整合中间过程也只有自己能体会了. 接下来开始说一下整合中的问题和技巧: 1,  jar包导入 c3p0(2个).jdbc(1个). ...

  4. Solr搭建大数据查询平台

    参考文章:http://www.freebuf.com/articles/database/100423.html 对上面链接的补充: solr-5.5.0版本已被删除,新url:http://mir ...

  5. sort排序

    /*问题 L: 使用sort排序题目描述标准库的sort函数给我们提供了一个很方便的排序的方法,光听别人说方便不顶事,得自己亲自实践一下才能体会到它的方便之处. 输入每组包含多组数据,每组数据第一行包 ...

  6. 常见电子元器件检测方法。——Arvin

    电子设备中使用着大量各种类型的电子元器件,设备发生故障大多是由于电子元器件失效或损坏引起的.因此怎么正确检测电子元器件就显得尤其重要,这也是电子维修人员必须掌握的技能.我在电器维修中积累了部分常见电子 ...

  7. aaa

    aaaa 来自为知笔记(Wiz)

  8. Apache Commons Lang

    http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/package- ...

  9. centos中安装字体

    转载自:http://blog.csdn.net/wlwlwlwl015/article/details/51482065 在使用phantomjs做自动化网页截图时,发现截图都没有文字.最后好久才发 ...

  10. mysql 5.7 忘记root密码解决方法

    1.修改配置文件 vim /etc/my.cnf 在[mysqld]节点添加 skip-grant-tables 2.重启mysql 3.用空密码进入 mysql -uroot 执行 update m ...