jQuery-1.9.1源码分析系列(六)延时对象应用——jQuery.ready

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

还记不记得jQuery初始化函数jQuery.fn.init中有这样是一个分支

//document ready简便写法$(function(){…})}elseif( jQuery.isFunction( selector ) ) {returnrootjQuery.ready( selector );

}

所以$(fn)===$(document).ready(fn)。

来看一下jQuery.fn.ready的源码

ready:function( fn ) {//Add the callbackjQuery.ready.PRomise().done( fn );returnthis;

}

很明显在jQuery.ready.promise函数中设置了延时,当延时对象解决的时候执行fn函数。

主要的处理流程:

创建一个延时对象,并将文档准备好后的处理事件添加到该延时对象成功事件列表上。

jQuery.ready.promise =function( obj ) {if( !readyList ) {

readyList=jQuery.Deferred();

...

}returnreadyList.promise( obj );

}

添加文档准备状态的监听函数(jQuery.ready.promise函数片段)

//标准浏览器支持DOMContentLoaded事件}elseif( document.addEventListener ) {//绑定DOMContentLoaded事件和响应函数,响应函数会解决延时document.addEventListener( "DOMContentLoaded", completed,false);//回退到window.onload事件绑定,所有的浏览器都支持window.addEventListener( "load", completed,false);//如果是IE事件模型}else{//确保在onload之前执行延时,可能时间比较迟,但是对于iframes来说比较安全document.attachEvent( "onreadystatechange", completed );//回退到window.onload事件绑定,所有的浏览器都支持window.attachEvent( "onload", completed );//如果IE并且不是一个frame//不断地检查,看是否该文件已准备就绪vartop =false;try{

top= window.frameElement ==null&&document.documentElement;

}catch(e) {}if( top &&top.doScroll ) {

(functiondoScrollCheck() {if( !jQuery.isReady ) {try{//Use the trick by Diego Perini//http://javascript.nwbox.com/IEContentLoaded/top.doScroll("left");

}catch(e) {returnsetTimeout( doScrollCheck, 50);

}//移除之前绑定的事件detach();//执行延迟jQuery.ready();

}

})();

}

}

一旦监听到文档准备完成,则调用jQuery.ready执行延时对象的成功回调列表:即所有通过jQuery.ready(fn)【或jQuery(fn)】方式添加的函数fn。

//ready事件处理函数completed =function( event ) {//readyState === "complete"在老版本IE上适用if( document.addEventListener || event.type === "load" ||document.readyState === "complete") {

detach();jQuery.ready();

}

},//清除ready事件绑定detach =function() {if( document.addEventListener ) {

document.removeEventListener("DOMContentLoaded", completed,false);

window.removeEventListener("load", completed,false);

}else{

document.detachEvent("onreadystatechange", completed );

window.detachEvent("onload", completed );

}

};

//处理当DOM准备完成jQuery.ready:function( wait ) {

...//设置DOM已经准备好的标志jQuery.isReady =true;

...//执行绑定的延时事件readyList.resolveWith( document, [ jQuery ] );//触发任何绑定的就绪事件if( jQuery.fn.trigger ) {

jQuery( document ).trigger("ready").off("ready");

}

}

整个过程就是如此。其中有一些小的知识点整理一下。

a. 文档加载状态document.readyStatedocument.readyState用来判断文档加载状态,是一个只读属性,可能的值有:

0-uninitialized:xml对象被产生,但没有任何文件被加载。

1-loading:加载程序进行中,但文件尚未开始解析。

2-loaded:部分的文件已经加载且进行解析,但对象模型尚未生效。

3-interactive:仅对已加载的部分文件有效,在此情况下,对象模型是有效但只读的。

4-complete:文件已完全加载,代表加载成功。

实例:

document.onreadystatechange = stateChange;//当页面加载状态改变的时候执行这个方法.functionstateChange() {

if(document.readyState == "complete"){//当页面加载状态为完全结束时进入

alert("文档加载成功")

}

}

但是,老版本的Firefox并不支持document.readyState【最新的Firefox已经支持了】。所以想要兼容所有浏览器监听文档准备完成分两种情况来处理:

-标准浏览器使用addEventListener添加DOMContentLoaded和load监听,任何一个事件被触发即可

-老版本IE浏览器使用attachEvent添加onreadystatechange和onload来监听,任何一个被触发,并且onreadystatechange时document.readyState === "complete"即可。

jQuery的处理也就是如此了

jQuery.ready.promise =function(){

...

//标准浏览器支持DOMContentLoaded事件elseif( document.addEventListener ) {//绑定DOMContentLoaded事件和响应函数,响应函数会解决延时document.addEventListener( "DOMContentLoaded", completed,false);//回退到window.onload事件绑定,所有的浏览器都支持window.addEventListener( "load", completed,false);//如果是IE事件模型}else{//确保在onload之前执行延时,可能时间比较迟,但是对于iframes来说比较安全document.attachEvent( "onreadystatechange", completed );//回退到window.onload事件绑定,所有的浏览器都支持window.attachEvent( "onload", completed );

...

}

}//ready事件处理函数completed =function( event ) {//readyState === "complete"在老版本IE上适用if(document.addEventListener || event.type === "load" || document.readyState === "complete") {

detach();

jQuery.ready();

}

}

b.doScroll检测文档加载完成这是Diego Perini 发现的一种检测IE是否加载完成的方式。详细链接

原理是当页面 DOM 未加载完成时调用 doScroll 方法时会产生异常。那么不断的取检测异常是否发生就可以知道文档有没有加载完成。当没有发生异常,表明文档加载完成了。

(functiondoScrollCheck() {if( !jQuery.isReady ) {try{//Use the trick by Diego Perini//http://Javascript.nwbox.com/IEContentLoaded/top.doScroll("left");

}catch(e) {returnsetTimeout(doScrollCheck, 50);

}//移除之前绑定的事件detach();//执行延迟jQuery.ready();

}

})();

如果觉得本文不错,请点击右下方【推荐】!

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航