萬盛學電腦網

 萬盛學電腦網 >> 數據庫 >> 數據庫綜合 >> jQuery源碼dom ready分析詳解

jQuery源碼dom ready分析詳解

今天為大家介紹的是jQuery源碼dom ready分析的相關內容,希望大家會喜歡。

一、前言

 在平時開發web項目時,我們使用jquery框架時,可能經常這樣來使用(document).ready(fn),(function(){}),這樣使用的原因是在浏覽器把DOM樹渲染好之前,javascript是無法操作沒渲染好的DOM節點。

其實除了(document).ready(fn),(function(){})寫法外,還有兩種讓dom渲染完之後執行js的寫法:

$(document).on('ready', fn2)

//通過on事件綁定函數,通過trigger觸發也可以達到j

Query.ready.promise().done(fn);

//通過這種方式也可以實現,jQuery.ready.promise()返回一個deferred對象,done(fn)添加回調方法

其中具體流程圖如下(自己簡單畫了一下,有錯請大家指正)

jQuery源碼dom ready分析

二、源碼部分(建議看這部分是,先理解清楚deferred,promise)

①$(function(){}) =>到rootjQuery.ready(selector);

我們知道,jQuery是由new jQuery.fn.init(selector, context, rootjQuery)實例出來的,對接了兩個參數,selector,context

// 構造函數,定義一個局部變量的jQueryjQuery = function (selector, context) {

// jQuery對象實際上是init的構造函數的引用return new jQuery.fn.init(selector, context, rootjQuery);

}

當我們使用(function()),則選擇器selector參數就變成了funciton,jQuery.fn.init函數判斷selector為Funtion時,又指向了

rootjQuery.ready(selector),就是(document).ready(fn);

rootjQuery = $(document)

jQuery.fn = jquery.prototype = {

init:function(selector,context,rootjQuery){

if (jQuery.isFunction(selector)) {

// 引用非靜態成員ready方法,等價於$(document).ready(selector)return rootjQuery.ready(selector);}

②$(document).on("ready",fn) => 到jQuery(document).trigger("ready").off("ready");

要理解$(document).on("ready",fn),我們要看ready部分

//擴展方法到jquery***

jQuery.extend({

/**

記錄監聽DOMContentLoaded事件(DOM是否加載完成),加載完成設置為true(類似一個開關)

* type {Boolean} 默認為false,表示頁面未加載完。當頁面DOM加載完成,設置為true */isReady: false,

/**

需要預加載的觀察者數量

* type {Number} 觀察者數量 */readyWait: 1,

/**

DOM加載完成,執行預加載

* @param {Boolean} wait 為true表示鎖定委托人,為false表示釋放委托人*/ready: function (wait) {

if (wait === true ? --jQuery.readyWait : jQuery.isReady) {

return;

}

// 檢測body是否存在(IE的一個bug),存在繼續向下執行,不存在進入語句,執行setTimeout定時器,直到body存在if (!document.body) {

return setTimeout(jQuery.ready);

}

// 開關,記錄DOM加載完成jQuery.isReady = true;

// 檢測所有的觀察者是否執行完成if (wait !== true && --jQuery.readyWait > 0) {

return;

}

// 委托人readyList通知觀察者,開始執行回調函數,並將document作為這些函數的上下文環境

readyList.resolveWith(document, [jQuery]);

// 檢測trigger方法是否存在,觸發綁定在document上的事件,執行完成之後並解綁

// $(document).on('ready', fn2);

// $(document).ready(fn1);

//這裡的fn1會先執行,自己的ready事件綁定的fn2回調後執行if (jQuery.fn.trigger) {

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

})

③$(document).ready(fn)

jQuery.fn = jquery.prototype = {

if (jQuery.isFunction(selector)) {

// 引用非靜態成員ready方法return rootjQuery.ready(selector);

},

ready: function (fn) {

// Add the callback

// promise類似一種事件委托,相當於一個創建委托人(已創建則無需創建,通過readyList判斷是否已創建),在DOM加載完成之後,委托人會通知觀察者done去執行回調函數fn

//調委托函數,返回deferred對象,添加done(fn)回調函數

jQuery.ready.promise().done(fn);

return this;

}

}

最後dom ready相關部分源碼詳細如下:

// 構造函數,定義一個局部變量的jQueryjQuery = function (selector, context) {

// jQuery對象實際上是init的構造函數的引用return new jQuery.fn.init(selector, context, rootjQuery);

} // 就緒事件處理程序completed = function (event) {

// document.readyState 判斷文檔加載狀態,'complete'代表文檔已經完全加載 if (document.addEventListener || event.type === "load" || document.readyState === "complete") {

detach();

//清理方法

jQuery.ready();//執行延遲加載方法 }

} // 清理DOMContentLoaded事件處理程序,為DOM事件做好准備,觸發jQuery.ready方法detach = function () {

// 標准的W3C監聽事件if (document.addEventListener) {

//刪除DOMContentLoaded監聽事件document.removeEventListener("DOMContentLoaded", completed, false);

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

} else {

// 針對IE,非標准的浏覽器

// 刪除onreadystatechange監聽事件document.detachEvent("onreadystatechange", completed);

window.detachEvent("onload", completed);

}

}; var readyList,rootjQuery=$(document);

jQuery.fn = jquery.prototype = { if (jQuery.isFunction(selector)) {

// 引用非靜態成員ready方法return rootjQuery.ready(selector);

},

ready: function (fn) {

// Add the callback

// promise類似一種事件委托,相當於一個創建委托人(已創建則無需創建,通過readyList判斷是否已創建),在DOM加載完成之後,委托人會通知觀察者done去執行回調函數fn

//調委托函數,返回deferred對象,添加done(fn)回調函數

jQuery.ready.promise().done(fn);

return this;

}}

//擴展方法到jquery****

jQuery.extend({

/**記錄監聽DOMContentLoaded事件(DOM是否加載完成),加載完成設置為true(類似一個開關)

* type {Boolean} 默認為false,表示頁面未加載完。當頁面DOM加載完成,設置為true */isReady: false,

/**

需要預加載的觀察者數量

* type {Number} 觀察者數量 */readyWait: 1,

/**

鎖定或釋放預加載委托人

* @param {Boolean} hold 為true表示鎖定預加載委托人,為false表示釋放委托人 */holdReady: function (hold) {

if (hold) {

jQuery.readyWait++;

} else {

jQuery.ready(true);

}},

/**

DOM加載完成,執行預加載

* @param {Boolean} wait 為true表示鎖定委托人,為false表示釋放委托人 */ ready: function (wait) {

// Abort if there are pending holds or we're already readyif (wait === true ? --jQuery.readyWait : jQuery.isReady) {

return;

}

// 檢測body是否存在(IE的一個bug),存在繼續向下執行,不存在進入語句,執行setTimeout定時器,直到body存在if (!document.body) {

return setTimeout(jQuery.ready);

} // 開關,記錄DOM加載完成jQuery.isReady = true;

// 檢測所有的觀察者是否執行完成if (wait !== true && --jQuery.readyWait > 0) {

return;

}

// 委托人readyList通知觀察者,開始執行回調函數,並將document作為這些函數的上下文環境

readyList.resolveWith(document, [jQuery]);

// 檢測trigger方法是否存在,觸發綁定在document上的事件,執行完成之後並解綁

// $(document).on('ready', fn2);

// $(document).ready(fn1);

//這裡的fn1會先執行,自己的ready事件綁定的fn2回調後執行if (jQuery.fn.trigger) {

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

}})

// 預加載委托函數jQuery.ready.promise = function (obj) {

// 判斷預加載委托人是否存在if (!readyList) {

// 創建一個預加載委托人readyList = jQuery.Deferred();

/**

W3C標准DOM浏覽器

* 0-uninitialized:XML 對象被產生,但沒有任何文件被加載。

* 1-loading:加載程序進行中,但文件尚未開始解析。

* 2-loaded:部分的文件已經加載且進行解析,但對象模型尚未生效。

* 3-interactive:僅對已加載的部分文件有效,在此情況下,對象模型是有效但只讀的。

* 4-complete:文件已完全加載,代表加載成功。 */// 檢測document內容是否加載完成,加載完成返回true,否者返回falseif (document.readyState === "

copyright © 萬盛學電腦網 all rights reserved