您的位置:首页 > Web前端 > JQuery

jQuery源码学习9——DOMReady加载

2015-11-25 11:25 411 查看
先将和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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: