使用jQuery库时,通常会使用ready函数。jQuery的ready函数不同与window.onload,如果你测试一下就会发现。

window.onload是在所有资源都加载完成时候触发,当资源比较大,比如图片文件较多的时候,window.onload的触发就会延迟很多,
影响用户体验。

jQuery.ready是在页面准备好之后就会触发,会先于window.onload事件。

jQuery是如何实现这个过程的呢?看完ready模块就明白了。

document.readyState 和 DOMContentLoaded

jQuery 借助document.readyState 与 DOMContentLoaded事件来实现ready函数。

当document.readyState=”complete” 的时候,DOM已经准备好了。但是,当页面加载二进制文件的时候如图片,会让这个事件慢于load事件。
使用document.readyState=”complete”只能做为一种参考,还必须提供额外的方法。(注:如果采用检测readyState = “interactive”会有bugChrisS discovered bug)

最保险的是使用DOMContentLoaded事件让判断,但是有的浏览器可能会不支持。所以使用load事件作为兼容。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
jQuery.ready.promise = function( obj ) {
// 先判断readyList是否已经初始化
// 没有初始化进行初始化
if ( !readyList ) {
readyList = jQuery.Deferred();
// 首先进行document.readyState判断
// 如果页面本来就也就加载完成了 直接调用jQuery.ready
if ( document.readyState === "complete" ) {
// 异步处理 让脚步有延迟处理的机会
// 虽然没有设置时间,但是setTimeout有最小时间,每个系统可能不同
setTimeout( jQuery.ready );
} else {
// 使用DOMContentLoaded 事件
document.addEventListener( "DOMContentLoaded", completed, false );
// 使用load 事件 实现兼容
window.addEventListener( "load", completed, false );
}
}
// 把obj转化为deferred对象返回
return readyList.promise( obj );
};

当完成DOMContentLoaded调用completed方法,completed中调用jQuery.ready()实现事件触发。

ready模块中使用了deferred对象,可以很方便的实现回调。

ready中有个holdReady方法,这个方法可以释放或者保持ready函数。就是释放的时候不会监听事件也会触发ready方法。

jQuery.ready中判断是否可以触发ready事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 处理判断dom是否准备好
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// 记住DOM已经准备好
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// 如果这儿有事件绑定那么执行它
readyList.resolveWith( document, [ jQuery ] );
// 触发ready函数
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger("ready").off("ready");
}
}

参考文档