jQuery之ready源碼分析


只要使用過jQuery的,想必對ready都不陌生,$(function(){})和$(document).ready(function(){})的使用更是習以為常。

要說到window.onload與document.ready的區別也能談出個一二,最重要的區別就是:

window.onload是在dom文檔樹以及所有文件都加載完成后,才執行;

而document.ready是,只要dom文檔樹加載完,就執行,且當dom文檔樹加載完就執行的好處就是,當頁面中的圖片等外部資源過多時,window.onload遲遲不能觸發,這時若還沒有綁定事件,用戶點擊按鈕時沒有反應,這不影響用戶體驗么。

咦,Jquery的ready這么牛逼,那Jquery是怎么實現ready這個函數的呢?我們不妨一起來探究探究。

以下Jquery.ready的源碼,截自於jQuery 1.12.0

 1 jQuery.ready.promise = function( obj ) {
 2     if ( !readyList ) {
 3 
 4         readyList = jQuery.Deferred();
 5 
 6         // Catch cases where $(document).ready() is called
 7         // after the browser event has already occurred.
 8         // we once tried to use readyState "interactive" here,
 9         // but it caused issues like the one
10         // discovered by ChrisS here:
11         // http://bugs.jquery.com/ticket/12282#comment:15
12         if ( document.readyState === "complete" ) {
13 
14             // Handle it asynchronously to allow scripts the opportunity to delay ready
15             window.setTimeout( jQuery.ready );
16 
17         // Standards-based browsers support DOMContentLoaded
18         } else if ( document.addEventListener ) {
19 
20             // Use the handy event callback
21             document.addEventListener( "DOMContentLoaded", completed );
22 
23             // A fallback to window.onload, that will always work
24             window.addEventListener( "load", completed );
25 
26         // If IE event model is used
27         } else {
28 
29             // Ensure firing before onload, maybe late but safe also for iframes
30             document.attachEvent( "onreadystatechange", completed );
31 
32             // A fallback to window.onload, that will always work
33             window.attachEvent( "onload", completed );
34 
35             // If IE and not a frame
36             // continually check to see if the document is ready
37             var top = false;
38 
39             try {
40                 top = window.frameElement == null && document.documentElement;
41             } catch ( e ) {}
42 
43             if ( top && top.doScroll ) {
44                 ( function doScrollCheck() {
45                     if ( !jQuery.isReady ) {
46 
47                         try {
48 
49                             // Use the trick by Diego Perini
50                             // http://javascript.nwbox.com/IEContentLoaded/
51                             top.doScroll( "left" );
52                         } catch ( e ) {
53                             return window.setTimeout( doScrollCheck, 50 );
54                         }
55 
56                         // detach all dom ready events
57                         detach();
58 
59                         // and execute any waiting functions
60                         jQuery.ready();
61                     }
62                 } )();
63             }
64         }
65     }
66     return readyList.promise( obj );
67 };

從上面的源碼中,可以看出,jQuery.ready主要通過以下幾個東東來判斷dom文檔樹是否加載完成:

(1)  document.readyState

(2)  DOMContentLoaded

(3)  onreadystatechange

(4)  doScroll

下面,我們就一步一步來解析

1、  document.readyState

readyState是個什么東東呢?它是document的一個屬性值,返回當前文檔的狀態,該屬性會根據文檔加載情況,返回如下幾個屬性值:

屬性值

意義

uninitialized

還未開始載入

loading

載入中

interactive

已加載,文檔與用戶可以開始交互

complete

載入完成

從屬性值,可得知,倘若當我們判斷document.readyState為complete,那么DOM文檔樹就是加載完畢。但,從上面源碼注釋(6--11行)中可以得知ChrisS發現了一個很特別的問題,所以我們在判斷document.readyState === ‘complete’后,執行jQuery.ready,需要延遲一下。但上面的代碼中,怎么沒有延遲時間呢?

那是因為倘若我們沒有設置延遲時間,setTimeout就會根據當前瀏覽器及操作系統,自動給它設定一個最小延遲時間。在《JavaScript忍者的秘密》中曾提到:

 

2、  DOMContentLoaded事件

從上面的源代碼注釋中,可以看出DOMContentLoaded是基於標准的瀏覽器的。

那么它的作用是什么呢?

當DOM文檔樹加載完成后,即觸發。

所以可以在標准的瀏覽器中判斷DOMContentLoaded,來判斷DOM樹,是否加載完成。

3、  onreadystatechange事件

上面的DOMContentLoaded事件是基於標准的瀏覽器的,那倘若不標准的呢,如IE,則使用onreadystatechange事件。

咦,怎么感覺如此熟悉。

XMLHttpRequest—>Ajax。想起來了么。在IE中onreadystatechange是私有化的,即所有元素都存在onreadystatechange事件,而W3C標准中,僅XMLHttpRequest對象中存在onreadystatechange事件。所以當事件觸發時,倘若onreadystatechange === complete,則可視為DOM樹加載完成。

4、  doScroll

從上面的源碼中的注釋(49--50行),可得,Diego Perini報告一種檢測IE下DOM文檔是否加載完成的方法,即,使用doScroll。

咦,上面onreadystatechange事件,不是能處理了嗎?!!

是的,但是它有個弊端,就是當頁面中存在圖片時,可能反而會晚於onload事件后,觸發。

為什么呢?

因為我們是依據onreadystatechange === complete來判斷的嘛,如果圖片沒加載或者正在加載中,那么onreadystatechange就不等於complete了哦。

所以為了保險起見,再用doScroll來檢測。

doScroll的原理就是,當頁面DOM未加載完成時,調用doScroll方法,會產生異常。所以利用try-catch來對doScroll捕獲異常就可以判斷DOM文檔是否加載完咯。

好了,jQuery.ready的源碼就解析到這兒,純屬自己觀點,有什么不對,請狠狠拍磚且交流,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM