JQuery源碼解析-Dom載入過程

來源:互聯網
上載者:User

標籤:

下面的幾個工具方法都是和dom載入有關,所以先從dom載入開始。

用到的方法:

  isReady:DOM是否已經載入完(內部使用)

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

  holdReady()::延遲DOM觸發

  ready():準備DOM觸發

  jQuery.ready.promise = function( obj ) {}檢測dom的非同步作業

先看一下jQuery和原生js載入方式有什麼不同:

     $(function () {        });        window.onload = function () {        };

jQuery是等待頁面中所有的dom載入完畢,而原生JavaScript的onload方法,則是等待頁面所有的元素載入完畢,

例如:一個img標籤,jQuery只等這個img標籤載入完畢,不必等到src中所引用的圖片載入完畢,但onload方法,則必須等到src中的圖片載入完畢才可以。

下面看一下jQuery的載入流程圖:

前面已經說過  $(function () {})和rootjQuery.ready( selector )是相等的,也就是說$(function () {})這種形式寫法,其實最後也被轉換成rootjQuery.ready( selector )。

而rootjQuery.ready( selector )這個執行個體方法裡:

ready: function( fn ) {        // Add the callback        jQuery.ready.promise().done( fn );        return this;    },

又是調用的工具方法中的jQuery.ready.promise().done( fn ),所以先從這個方法開始分析,代碼如下:

jQuery.ready.promise = function( obj ) {    if ( !readyList ) {        readyList = jQuery.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" ) {            // 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 );            // A fallback to window.onload, that will always work            window.addEventListener( "load", completed, false );        }    }    return readyList.promise( obj );};

這個方法中有判斷:

首先判斷如果document.readyState === "complete" ,那麼已經代表了在運行到這時,頁面中的dom已經載入完畢了,然後運行setTimeout( jQuery.ready )

這裡用到了setTimeout方法,是為了相容ie的hack方法,具體原因可以看一下注釋中的網址。

如果readyState 不等於complete,那麼就會添加兩個回調方法,這裡添加兩個的原因,是因為在Firefox等瀏覽器中,會緩衝load方法,所以就會先調用load方法,所以這裡添加了兩個回調,保證了在第一時間內調用complete方法。

下面在看一下complete方法中寫了什麼:

// The ready event handler and self cleanup method    completed = function() {        document.removeEventListener( "DOMContentLoaded", completed, false );        window.removeEventListener( "load", completed, false );        jQuery.ready();    };

通過源碼可以看到,這裡無論哪種方法進行了回調,都會在這裡將事件解除綁定,所以這裡也就保證了只回調一次,最後又調用了jQuery.ready()方法。

這也說明,其實在jQuery.ready.promise方法中,無論條件如何,都會調用jQuery.ready()方法。

在說ready()方法前,先來說明一下holdReady方法。

這個方法是阻塞dom載入的,看一下這個例子:

a.js:

alert(1);

調用頁面:

$.getScript("a.js", function () {        })
 $(function () {
  alert(2);
});

這時運行,查看結果發現,其實先彈出的是2,然後才是1,這顯然和我們的預期不一致,一般我們在頁面中引用js的時候,都是想使用這個js檔案,然後在進行下面的操作。

但因為是非同步,所以當前的結果表明,是最後才運行了a.js中的內容。

所以這時就用到了holdReady方法:

            $.holdReady(true);            $.getScript("a.js", function () {                 $.holdReady(false)            })            $(function () {                               alert(2);            });

這時頁面的運行結果就正確了。

源碼:

// Is the DOM ready to be used? Set to true once it occurs.    isReady: false,    // A counter to track how many items to wait for before    // the ready event fires. See #6781    readyWait: 1,    // Hold (or release) the ready event    holdReady: function( hold ) {        if ( hold ) {            jQuery.readyWait++;        } else {            jQuery.ready( true );        }    },

可以看到,方法內部有個計數器,這也就說明了,當頁面載入多個js檔案時,可以進行多次調用,保證所有檔案都載入完畢,才可以繼續運行。

如果傳入的參數為false,則執行ready方法,並傳入true:

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 ] );        // Trigger any bound ready events        if ( jQuery.fn.trigger ) {            jQuery( document ).trigger("ready").off("ready");        }    },

第一個判斷,如果為true,則將計數器減一,否則判斷isReady變數

第二個判斷,如果計數器還大於0的話,則繼續等待。

到readyList.resolveWith( document, [ jQuery ] ); 這句代碼,就開始運行延時的方法了,第一個參數指定節點,第二個是將jQuery傳入

可以通過下面的代碼查看:

 $(function (arg) {                console.log(this);                console.log(arg);            })

運行結果可以看到 this:document arg:jQuery對象。

下面看最後一段代碼

        // Trigger any bound ready events        if ( jQuery.fn.trigger ) {            jQuery( document ).trigger("ready").off("ready");        }

這段代碼是考慮到另一種載入方式:

 $(document).on(‘ready‘, function () {                alert(1);            })

如果將這段代碼注釋,可以看到,這種方式就無法運行了。

所以這也說明了,jQuery其實有三種寫法:

         $(function () {})            $(document).ready(function () { })            $(document).on(‘ready‘, function () {})

 

JQuery源碼解析-Dom載入過程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.