在jQuery對象創建的時候,即init函數中,有處理這麼一種參數情況,當selector爲函數時,$(function(){ })
表示跟$(document).ready(function(){ })
是一樣的情況。
源碼是這樣的:
if(jQuery.isFunction(selector))
{
//rootjQuery = $(document);
return rootjQuery.ready(selector);
//相當於調$(document).ready()方法。
}
$.fn.ready
上面的$(document).ready()
相當於調jQuery的實例方法。我們來看看實例方法ready()的源碼:
ready: function(fn){
jQuery.bindReady();
readyList.add(fn);
return this;
}
代碼只有短短三行,下來一個一個看調用的函數。
bindReady
函數相當於監聽文檔加載完成的函數,即添加事件處理程序。
bindReady: function(){
//文檔的狀態主要有五種情況:
//UnInitialized:未開始加載
//Loading:加載程序進行中,但是文件還沒有被解析;
//Loaded:部分文件加載並解析,但是文檔對象模型(DOM)還暫未生效
//Interactive:只對已加載的文件有效且DOM有效但是隻讀;
//Complete: 文件已全部加載,表示加載成功。
if ( document.readyState === "complete" ) {
return setTimeout( jQuery.ready, 1 ); //處理IE的問題,它會提前觸發ready,所以延遲一下
}
if ( document.addEventListener ) {
//添加事件處理程序,監聽DOMContentLoaded事件
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
//爲什麼還要監聽load事件?因爲load事件是可以緩存的,有緩存的話,會先觸發load事件
window.addEventListener( "load", jQuery.ready, false );
} else if ( document.attachEvent ) {
//IE事件處理函數
document.attachEvent( "onreadystatechange", DOMContentLoaded );
window.attachEvent( "onload", jQuery.ready );
// 後面這部分暫時沒大看懂
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
}
上面的DOMContentLoaded事件處理函數如下:
if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
jQuery.ready();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
};
}
可以看到,上面不論是哪種情況分支,都會最終調jQuery.ready()方法。也就是當文檔加載完成時,總是會觸發jQuery.ready
函數
ready: function( wait ) {
//表示延遲事件處理函數,其中jQuery.readywait是由jQuery.holdReady函數控制的。
if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
if ( !document.body ) {
return setTimeout( jQuery.ready, 1 );
}
//表示DOM加載完成,並記錄下狀態
jQuery.isReady = true;
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
//執行回調函數,這部分函數是在底層模塊的回調部分實現的,後面看到的時候再梳理。
readyList.fireWith( document, [ jQuery ] );
//觸發ready函數
//考慮到這種用法:$(document).on('ready', function(){})
if ( jQuery.fn.trigger ) {
jQuery( document ).trigger( "ready" ).off( "ready" );
}
}
}
以上是Ready部分的整體實現。下來再做一個簡單的梳理:
$(function(){
console.log("Ready");
})
相當於調用$(document).ready(function(){ console.log("Ready") })
;
而裏面的回調函數function(){ console.log("Ready") }
是在頁面加載完成之後觸發,所以按照我們之前事件的思路,要先監聽事件,添加事件處理函數,然後在事件被觸發的時候才能去執行回調函數。而Ready的源碼也是這種思路。
首先bindReady
函數監聽文檔加載完成事件,並定義事件處理函數complete
;
同時將回調函數加入到ReadyList中,這個是爲了管理多個回調函數。因爲jQuery中可以多次使用$(function(){ })
。
下來就是當頁面加載成功時,調用jQuery.ready()
函數,去分別將ReadyList中的回調函數觸發,這部分調的是ReadyList.fireWith()
方法,這個到後面看回調模塊時會再整理。