jQuery源码学习9——DOMReady加载

先将和ready相关的代码都归纳出来

    function jQuery(a,c) {
        if ( a && a.constructor == Function && jQuery.fn.ready ){
            return jQuery(document).ready(a);
        }
    }
    jQuery.fn.extend({
        ready: function(f) {
            if ( jQuery.isReady )
                f.apply( document );
            else {
                jQuery.readyList.push( f );
            }        
            return this;
        }
    });
    jQuery.extend({
        isReady: false,
        readyList: [],
        ready: function() {
            if ( !jQuery.isReady ) {
                jQuery.isReady = true;
                if ( jQuery.readyList ) {
                    for ( var i = 0; i < jQuery.readyList.length; i++ )
                        jQuery.readyList[i].apply( document );
                    jQuery.readyList = null;
                }
            }
        }
    });
    new function(){
        if ( jQuery.browser.mozilla || jQuery.browser.opera ) {
            document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
        } else if ( jQuery.browser.msie ) {
            document.write("<scr" + "ipt id=__ie_init defer=true " + 
                "src=//:></script>");
            var script = document.getElementById("__ie_init");
            script.onreadystatechange = function() {
                if ( this.readyState == "complete" )
                    jQuery.ready();
            };
            script = null;
        } else if ( jQuery.browser.safari ) {
            jQuery.safariTimer = setInterval(function(){
                if ( document.readyState == "loaded" || 
                    document.readyState == "complete" ) {
                    clearInterval( jQuery.safariTimer );
                    jQuery.safariTimer = null;
                    jQuery.ready();
                }
            }, 10);
        } 
        jQuery.event.add( window, "load", jQuery.ready );    
    }

jQuery里面的初始化已经在document或者script上绑定了一些事件

FF和opera下,document的DOMContentLoaded完成之后触发jQuery.ready事件

IE下,script的onreadystatechange事件中script.readyState是complete的时候触发jQuery.ready事件

webkit内核下貌似是手动实现了一个onreadystatechange事件,开了一个定时器,每隔10ms监听一下document上的readyState是否为complete

如果是complete的话,触发jQuery.ready事件,顺便把这个定时器干掉

最后做了一个万全的方案,window对象的onload方法触发时,也就是页面中所有东西都加载完的时候触发jQuery.ready事件

通过上述分析可以发现不管在哪个浏览器下都有两次机会触发jQuery.ready事件

第一次就是在DOM结构加载完毕(DOMContentLoaded完毕或者readyState为complete)

第二次就是在页面所有资源加载完毕(window.onload)

这两次触发jQuery.ready是相互竞争的

如果不做任何处理,一定会重复两次去执行jQuery.ready

所以jQuery初始化的时候加了一个isReady的一个静态方法

初始值为false

在触发jQuery.ready的时候,先if判断了一下jQuery.ready的值

如果jQuery.ready的值是false的话,证明之前没有触发过jQuery.ready

jQuery.ready里面马上把jQuery.isReady变成true,代表触发过了

那第二次再触发jQuery.ready的时候里面再判断jQuery.isReady

变成了true的话就什么都不做了

我们关键看jQuery.ready是false,即之前没有触发过的情况

在这种情况下进一步判断jQuery.readyList

jQuery.readyList也是在jQuery初始化的时候定义的

初始值是一个空数组

我们在以$(function(){})或者$(document).ready(function(){})调用的时候都会在某个时机把里面的函数添加到jQuery.readyList中

数组不管空还是不空都是真,所以这个判断始终为真

进入if判断之后就循环jQuery.readyList里面的所有函数

依次执行每个函数

或许是考虑到jQuery.readyList在执行完以后就没什么用了,所以就把readyList直接赋值为null了

我们通过$(function(){})或者$(document).ready(function(){})的调用方式希望页面加载完毕触发里面的函数时

会调用jQuery.fn.ready这个方法

这个jQuery.fn.ready里面的实现虽然只有短短几行代码,但很值得分析一下

里面通过判断jQuery.isReady的值来执行不同的操作

前面分析到jQuery.isReady初始化为false

而且是在DOMContentLoaded/readyState=="complete"/onload任何一种完事了之后变成true的

在jQuery.fn.ready里面

jQuery.isReady是false的时候我们是把事件function添加到readyList队列里面

jQuery.isReady是true的时候我们直接执行了function

这里就不得不佩服jQuery作者英明的思路了

isReady是false的时候放在队列里面的方法在DOMContentLoaded/readyState=="complete"/onload完毕之后在jQuery.ready()中去挨个执行

isReady是true的时候,页面已经加载完毕,所以就直接执行function了

还是用例子说更直观一些,例如下面的代码

    $(aaa);
    $(bbb);
    $(ccc);
    $(ddd);
    function aaa(){
        alert(1);
    }
    function bbb(){
        alert(2);
    }
    function ccc(){
        alert(3);
    }
    function ddd(){
        $(eee);
    }
    function eee(){
        alert(4);
    }

最开始我们引入的jQuery执行的时候其实已经绑定了DOMContentLoaded/readyState=="complete"/onload这一系列事件

那从引入的jQuery文件执行完毕到这些事件触发并执行jQuery.ready之前js会接着往下执行$(aaa) $(bbb) $(ccc)...

假如执行到$(bbb)的时候

DOMContentLoaded/readyState=="complete"/onload里面中的一个触发了

那在jQuery.ready执行的时候jQuery.readyList里面就会有aaa bbb两个函数

为什么是这两个呢?

因为在DOMContentLoaded/readyState=="complete"/onload触发之前,每执行一次$(xxx)

判断之后发现jQuery.isReady是false,就会将aaa bbb这两个函数push到readyList中了

此后jQuery.isReady的值就是true了

再执行$(ccc) $(ddd)的话,判断之后发现jQuery.isReady是true

ccc和ddd就会直接执行

执行ddd的时候发现ddd里面又执行了$(eee)

同样jQuery.isReady仍然是true,所以还是会直接执行eee

原文地址:https://www.cnblogs.com/zhaohuiziwo901/p/4994104.html