Jquery1.9.1源码分析系列(六)延时对象应用之jQuery.ready

  作者:bea

还记不记得jQuery初始化函数jQuery.fn.init中有这样是一个分支 //document ready简便写法$(function(){…})} else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector );}  所以$(fn)===$(document).ready(fn)。  来看一下jQuery.fn.ready的源码ready: function( fn )

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




//document ready简便写法$(function(){…})
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
  所以$(fn)===$(document).ready(fn)。
  来看一下jQuery.fn.ready的源码
ready: function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn );
return this;
}


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


  主要的处理流程:


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




jQuery.ready.promise = function( obj ) {
  if ( !readyList ) {
    readyList = jQuery.Deferred();
    ...
  }
return readyList.promise( obj );
}


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




//标准浏览器支持DOMContentLoaded事件
} else if ( 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
//不断地检查,看是否该文件已准备就绪
var top = false;
try {
top = window.frameElement == null && document.documentElement;
} catch(e) {}
if ( top && top.doScroll ) {
(function doScrollCheck() {
if ( !jQuery.isReady ) {
try {
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll("left");
} catch(e) {
return setTimeout( 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.readyState


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


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

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

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

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

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


  实例:




document.onreadystatechange = stateChange;//当页面加载状态改变的时候执行这个方法.
function stateChange() {
 
  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事件
  else if ( 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 方法时会产生异常。那么不断的取检测异常是否发生就可以知道文档有没有加载完成。当没有发生异常,表明文档加载完成了。          




(function doScrollCheck() {
if ( !jQuery.isReady ) {
try {
// Use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
top.doScroll("left");
} catch(e) {
return setTimeout( doScrollCheck, 50 );
}
//移除之前绑定的事件
detach();
//执行延迟
jQuery.ready();
}
})();


以上所述是脚本之家小编给大家介绍的Jquery1.9.1源码分析系列(六)延时对象应用之jQuery.ready的全部内容,希望大家喜欢。




有用  |  无用

猜你喜欢