天天看點

jquery源碼 DOM加載一、$(function(){})和原生window.onload的關系二、jQurey如何實作DOM ready的三、源碼整體實作邏輯四、實作細節

jQuery版本:2.0.3

DOM加載有關的擴充

isReady:DOM是否加載完(内部使用) 

readyWait:等待多少檔案的計數器(内部使用)

holdReady():推遲DOM觸發

ready():準備DOM觸發。

jQuery.ready.promise=function(){};  監聽DOM的異步操作(内部使用)

這個在面試中也是經常會被問到的。從下面幾個角度來分析一下它們的差別

頁面加載,先加載節點,再加載檔案,比如img檔案,flash等。

$(function(){})DOM加載完執行。可能DOM元素關聯的東西并沒有加載完。

window.onload等節點和檔案都加載完執行。

對應的事件監聽

jQuery用的是DOMContentLoaded事件。

DOMDContentLoaded:原生DOM加載事件,這個事件觸發代表DOM加載完了。

我之前寫過一篇文章的頁面加載時間分析裡也有提到。

onload對應的是load事件。

window.onload不能寫多個,後面的會覆寫前面的。

$(function(){})可以寫多個。都會執行 。

$(function(){})是$(document) .ready(function(){});的簡化寫法。

window.onload沒有簡化寫法。

jQuery直接調用DOMContentLoaded來實作DOM的ready。但是DOMContentLoaded和onLoad一樣,浏覽器隻執行一次,jQuery用什麼判斷是否已經執行過呢?document.readyState就是判斷這個的依據。

readyState是document的屬性,總共有3個值:

loading:文檔正在加載中

interactive:文檔已經加載完成,正在進行css和圖檔等資源的加載

complete:文檔的是以資源加載完成

判斷完之後如何回調呢?就是用Promise。jQuery通過new一個$.Deferred(promise)對象來實作對DOM的ready的回調,在DOMContentLoaded中将這個promise給resolve掉,這樣就執行了之前注冊的回調函數,同時後面新注冊的回調也會立刻執行。

但是在調用promise之前,jQuery執行了一次setTimeout,因為jQuery.Promise是不會産生異步的,這和标準的promise規範是不一樣的,所有jQuery自己又手動做了一次setTimeout來實作異步。這樣使得無論使用在DOM的ready之前注冊的回調還是之後注冊的回調都會在異步中執行。

$(fn)==>new一個 jQuery.fn.init(fn)==>傳回$(document).ready( fn)。也就是說

$(function(){}) =》

調用$(document).ready(function(){})=》

相當于$().ready(fn)執行個體方法=》

調用的jQuery.ready.promise().done(fn)=》

jQuery.ready.promise中不管if還是else最終都是調用jQuery.ready(),并傳回promise=》

jQuery.ready()裡面重點是readyList.resolveWith( document, [ jQuery ] );已完成。至此DOM加載完畢就可以調用fn了。

jquery源碼 DOM加載一、$(function(){})和原生window.onload的關系二、jQurey如何實作DOM ready的三、源碼整體實作邏輯四、實作細節

如果DOM已經加載完成了,調用jQuery.ready()這個工具方法;

如果DOM沒加載完,監聽DOMContentLoaded事件和load事件,等事件發生時回調completed(),最終也是調用jQuery.ready()這個工具方法;

completed回調函數如下,最終調用的也是jQuery.ready()。 

先做個測試:

jquery源碼 DOM加載一、$(function(){})和原生window.onload的關系二、jQurey如何實作DOM ready的三、源碼整體實作邏輯四、實作細節

再做個測試:

除了$(function(){});$(document).ready(function(){}),也可以把ready當做事件來處理如下。

之是以會自動彈出123,是因為在jQuery源碼中用這句話jQuery( document ).trigger("ready").off("ready");來主動觸發了ready事件,觸發後再取消掉。

跟ready的參數有關的有一個holdReady()。

先做個測試

可以推遲,也可以釋放推遲,釋放了以後就可以觸發了。

這個有什麼用?

比如:

很多時候引入外部檔案的時候,都想等外部檔案或者插件加載完,再去觸發操作,操作可能用到a.js。現在這個順序不對,會出問題。

怎樣解決這個問題?用holdReady()方法。

再深入一點,holdReady() 要針對的檔案可能不止一個,有很多個,是以要等所有的檔案都加載完再執行,是以源碼中有一個計數的readyWait。

源碼中定義了一個等待棧變量——readyWait,每次執行$.holdReady(true)都會增加壓棧,而每次$.holdReady()執行都會彈棧,等空棧的時候就執行jQuery.ready函數,即将promise給resolve掉。

本文轉自帥氣的頭頭部落格51CTO部落格,原文連結http://blog.51cto.com/12902932/1926151如需轉載請自行聯系原作者

sshpp

繼續閱讀