上次分析了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" );
        }
    }
},

最新文章

  1. CRM 安全证书到期操作命令
  2. webpack使用的心得
  3. 第一次使用Android Studio时你应该知道的一切配置
  4. python thread 多线程
  5. 使用Eclipse进行远程调试【转】
  6. ASP.NET MVC4 部分视图
  7. C/C++中产生随机数(rand,srand用法)
  8. DNS笔记 DNS区域集成到 Active Directory
  9. Oralce常用维护命令
  10. eclipse[日文版] 的SVN 上传步骤
  11. C# typeof Gettype is as &拆箱 装箱
  12. LindDotNetCore~授权中间件的介绍
  13. vs2012 aps.net 4.5尚未在web服务器上注册,您需要手动将Web服务器配置为
  14. Golang垃圾回收机制(二)
  15. ZJOI2019Day1AFO记
  16. 关于WPF中Popup中的一些用法的总结
  17. Spring MVC基础知识整理➣数据校验与格式化
  18. 在 Visual Studio 生成项目时,会发现一些 dll 并没有被复制到输出目录,导致最终程序的执行错误
  19. 利用MATLAB截取一张复杂图片中想要的区域
  20. Python学习之路目录(收藏整理)

热门文章

  1. LINUX安全加固规范
  2. Vs2012(Vs2013) 编译 64位 Qt (动态库), 并使用自编译Qt建立工程(悲催经历)。(含遗留问题)
  3. Cocos2d-x 核心概念 - 导演(Director)
  4. Web API后端调用接口 (Get,POST,Put,Delete)
  5. WordPress 插件推荐
  6. 实现table的单线边框的办法
  7. TestNG Study Note 1 - Eclipse 插件安装
  8. Oralce 账户被锁后的解决办法
  9. Linux 常见问题解决办法
  10. JS巧计__轮播