jquery中,等待DOM加载完成再执行的方法ready事件,相信大家经常使用该事件,今天,我们来看下jquery源码中是如何实现该功能的。
一、实例
首先看下,如何使用ready事件:
$(document).ready(function(){
console.log(1);
});
等DOM加载完成后,执行匿名函数,在控制台中打印1。
首先了解一下DOMContentLoaded与window.load()。
DOMContentLoaded是DOM构建完成后触发,window.onload()是等所有的内容加载完成,例如图片等等。DOMContentLoaded事件先触发,后触发window.onload()事件。
二、源码解析:
1.函数及变量初始化
jQuery.extend({
isReady: false, //DOM是否加载完毕,初始化为false
readyWait: 1, //需要等待的事件,初始化为1
// Hold (or release) the ready event
holdReady: function( hold ) { //是否要hold住ready事件。
},
// Handle when the DOM is ready
ready: function( wait ) { //ready函数,执行ready事件是调用
}
});
/**
* The ready event handler and self cleanup method
*/
function completed() { //DOM完成后触发
}
jQuery.ready.promise = function( obj ) { //ready事件调用的函数
}
完成工具方法的扩展后,后面代码立即执行了:
2.执行 jQuery.ready.promise()
jQuery.ready.promise();
然我们看下该函数内部代码
jQuery.ready.promise = function( obj ) {
if ( !readyList ) { //第一次执行时readylist为undefined,进入if
readyList = jQuery.Deferred(); //readyList为Deferred对象
// Catch cases where $(document).ready() is called after the browser event has already occurred.
// We once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if ( document.readyState === "complete" ) { //如果DOM已经加载完了,我们不再触发complete事件,直接走ready
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready );
} else {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", completed, false ); //给文档添加DOMContentLoaded事件
// A fallback to window.onload, that will always work
window.addEventListener( "load", completed, false ); //如果DOMContentLoade不执行,以此为备用,总是执行
}
}
return readyList.promise( obj ); //返回状态不可改的Deferred对象
};
3.执行jquery实例ready事件
当工具方法都初始化完之后,开始执行$(document).ready()中的ready().
jQuery.fn.ready = function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn ); //jQuery.ready.promise()函数,由于初始化工具方法时,已经执行过一遍,代码会直接返回Deferred对象。
return this; //把入参添加到done中
};
4.DOM树构造完成
触发complete事件
function completed() {
document.removeEventListener( "DOMContentLoaded", completed, false ); //去除绑定的函数
window.removeEventListener( "load", completed, false );
jQuery.ready(); //执行工具方法的ready
}
5.执行工具方法的ready方法
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { //如果等待或者已经等待后了,跳过
return;
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] ); //触发resolveWith执行done中添加的函数
// Trigger any bound ready events
if ( jQuery.fn.triggerHandler ) {
jQuery( document ).triggerHandler( "ready" );
jQuery( document ).off( "ready" );
}
}
});