js便簽筆記(6)——jQuery中的ready()事件為何需要那么多代碼?


前言:

ready()事件的應用,是大家再熟悉不過的了,學jQuery的第一步,最最常見的代碼:

jQuery(document).ready(function () { });
jQuery(function () { });
$(document).ready(function () { });
$(function () { });

以上四行代碼的目的和效果都一樣——待DOM加載完成之后,執行傳入的function函數。

再對jquery稍微熟悉一點的朋友可能知道,這里的“待DOM加載完成”,不是window.onload事件,window.onload是指“DOM加載完成 + DOM相關的文件下載完成”。這里的“DOM加載完成”,不包括“DOM相關的文件加載完成”。相關的事件是:

  • DOMContentLoaded事件(IE9+以及其他瀏覽器)
  • onreadystatechange事件(IE9以下瀏覽器)

問題就在這里。如果知道了這兩個事件,那么把傳入的function函數關聯到這兩個事件上就行了,而jquery中與ready相關的代碼洋洋灑灑的寫了那么多,至於上百行代碼。這是為何?

原因在於以下幾點:

 

2. 存儲結構——基於異步隊列設計:

先看以下代碼:

        //應用ready事件
        $(function () {
            alert(10);
        });
        $(function () {
            alert(20);
        });
        $(function () {
            alert(30);
        });

以上代碼連續應用了三次ready方法,其實jquery是用本身的jquery.callbacks來處理的。主要代碼如下:

readyList = jQuery.Callbacks( "once memory" );
readyList.add( fn );
readyList.fireWith( document, [ jQuery ] );

"once":代表add進來的函數只被調用一次;

"memory":代表一旦readylist被執行過一次,那么它后續添加進來的函數會立即按照執行時候的環境和參數執行。

 

3. 巧妙的事件綁定:

以IE9+和其他瀏覽器支持的DOMContentLoaded為例。先看代碼:

        // Mozilla, Opera and webkit nightlies currently support this event
        if ( document.addEventListener ) {
            // Use the handy event callback
            document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );

            // A fallback to window.onload, that will always work
            window.addEventListener( "load", jQuery.ready, false );
        }

   DOMContentLoaded
= function() { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); };

根據以上代碼可見,最終DOMContented事件執行的,其實是jQUery.ready()這個工具函數。(注意,jquery.ready()和jquery(document).raedy()不一樣!!,前者是工具函數,后者是實例函數。)

這里是通過定義一個DOMContentLoaded函數作為橋梁來執行jquery.ready()函數的,這樣做的目的就是為了即使的remove掉document的DOMContentLoaded事件的引用。

document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );

單獨把這兩行摘出來,可以看明白,add完了之后,接着remove掉了,在這中間,巧妙的執行了jquery.ready(),這種用法值得學習!

反過來,如果像以下代碼那么樣實現,document的DOMContentLoaded事件的引用將無法及時刪除。

//反例
document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );

 

 

另外,除了通過瀏覽器的DOMContentLoaded/onreadystatechange方法可以調用jquery.ready()函數之外,還有一種巧妙的方式調用jquery.ready()函數。

在IE9以下的瀏覽器中,如果當前頁面是頂層(即沒有包含在iframe和friame元素中),調用html.doScroll(),直到不拋出異常,即可調用jquery.ready()函數。

 1     if ( document.documentElement.doScroll && toplevel ) {
 2                 doScrollCheck();
 3             }
 4             
 5     /*省略*/
 6     
 7     try {
 8         // If IE is used, use the trick by Diego Perini
 9         // http://javascript.nwbox.com/IEContentLoaded/
10         document.documentElement.doScroll("left");
11     } catch(e) {
12         setTimeout( doScrollCheck, 1 );
13         return;
14     }
15 
16     // and execute any waiting functions
17     jQuery.ready();

 

4. 事件執行:

上文中講到,可以通過瀏覽器的DOMContentLoaded/onreadystatechange事件,以及對html.doScroll()的檢測來調用jquery.ready()工具函數,jquery.ready()最終將會調用異步隊列的firewith()方法觸發傳入的所有事件。如果是通過js手動調用,也可以通過jquery事件系統來調用。

readyList.fireWith( document, [ jQuery ] );

if ( jQuery.fn.trigger ) {
                jQuery( document ).trigger( "ready" ).off( "ready" );
            }

 

其實這其中還有個jquery.holdready()方法用來延遲調用,不過比較簡單,也不常用,此處不說了。

 

5. 總結:

可見,jQuery中的ready()事件並不是我們看起來那么簡單,了解其原理的同時,也應該想想我們在自己設計系統的時候,考慮的時候全面。

  • 它用到了異步隊列,使得使用者可以多次調用,順序執行;
  • 它的事件綁定考慮到了各種情況,而又充分考慮了資源的釋放;
  • 它同時考慮了瀏覽器調用的情況,和js手動調用的情況。

個人感受:想了解js到底該怎么用,了解js的源碼和設計,是一個捷徑。

 


免責聲明!

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



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