jQuery-1.9.1源碼分析系列(六) 延時對象應用——jQuery.ready


  還記不記得jQuery初始化函數jQuery.fn.init中有這樣是一個分支

//document ready簡便寫法$(function(){…})
} else if ( jQuery.isFunction( selector ) ) {
    return rootjQuery.ready( selector );
}

  所以$(fn)===$(document).ready(fn)

  來看一下jQuery.fn.ready的源碼

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

    return this;
}

  很明顯在jQuery.ready.promise函數中設置了延時,當延時對象解決的時候執行fn函數。

  主要的處理流程:

  創建一個延時對象,並將文檔准備好后的處理事件添加到該延時對象成功事件列表上

jQuery.ready.promise = function( obj ) {
  if ( !readyList ) {
    readyList = jQuery.Deferred();

    ...

  } return readyList.promise( obj ); }

  添加文檔准備狀態的監聽函數(jQuery.ready.promise函數片段)

    //標准瀏覽器支持DOMContentLoaded事件
    } else if ( document.addEventListener ) {
            //綁定DOMContentLoaded事件和響應函數,響應函數會解決延時
            document.addEventListener( "DOMContentLoaded", completed, false );

            //回退到window.onload事件綁定,所有的瀏覽器都支持
            window.addEventListener( "load", completed, false );

    //如果是IE事件模型
    } else {
            //確保在onload之前執行延時,可能時間比較遲,但是對於iframes來說比較安全
            document.attachEvent( "onreadystatechange", completed );

            //回退到window.onload事件綁定,所有的瀏覽器都支持
            window.attachEvent( "onload", completed );

            //如果IE並且不是一個frame
            //不斷地檢查,看是否該文件已准備就緒
            var top = false;
            try {
                top = window.frameElement == null && document.documentElement;
            } catch(e) {}
            if ( top && top.doScroll ) {
                (function doScrollCheck() {
                    if ( !jQuery.isReady ) {
                        try {
                            // Use the trick by Diego Perini
                            // http://javascript.nwbox.com/IEContentLoaded/
                            top.doScroll("left");
                        } catch(e) {
                            return setTimeout( doScrollCheck, 50 );
                        }

                        //移除之前綁定的事件
                        detach();

                        //執行延遲
                        jQuery.ready();
                    }
                })();
            }
        }

  一旦監聽到文檔准備完成,則調用jQuery.ready執行延時對象的成功回調列表:即所有通過jQuery.ready(fn)【或jQuery(fn)】方式添加的函數fn。

//ready事件處理函數
completed = function( event ) {
    // readyState === "complete"在老版本IE上適用
    if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
        detach();
        jQuery.ready();
    }
},
//清除ready事件綁定
detach = function() {
    if ( document.addEventListener ) {
        document.removeEventListener( "DOMContentLoaded", completed, false );
        window.removeEventListener( "load", completed, false );

    } else {
        document.detachEvent( "onreadystatechange", completed );
        window.detachEvent( "onload", completed );
    }
};
//處理當DOM准備完成
jQuery.ready: function( wait ) {      
    ...        
    //設置DOM已經准備好的標志      
    jQuery.isReady = true;    
    ...   
    //執行綁定的延時事件   
    readyList.resolveWith( document, [ jQuery ] );   
    //觸發任何綁定的就緒事件   
    if ( jQuery.fn.trigger ) {     
        jQuery( document ).trigger("ready").off("ready");   
    }  
}

   整個過程就是如此。其中有一些小的知識點整理一下。

 

a. 文檔加載狀態document.readyState


  document.readyState用來判斷文檔加載狀態,是一個只讀屬性,可能的值有:

  0-uninitialized:XML 對象被產生,但沒有任何文件被加載。
  1-loading:加載程序進行中,但文件尚未開始解析。
  2-loaded:部分的文件已經加載且進行解析,但對象模型尚未生效。
  3-interactive:僅對已加載的部分文件有效,在此情況下,對象模型是有效但只讀的。
  4-complete:文件已完全加載,代表加載成功。

  實例:

document.onreadystatechange = stateChange;//當頁面加載狀態改變的時候執行這個方法.
function stateChange() {   
  
if(document.readyState == "complete"){ //當頁面加載狀態為完全結束時進入     
    alert("文檔加載成功")
  
  }
}

  但是,老版本的Firefox並不支持document.readyState【最新的Firefox已經支持了】。所以想要兼容所有瀏覽器監聽文檔准備完成分兩種情況來處理:

  - 標准瀏覽器使用addEventListener添加DOMContentLoaded和load監聽,任何一個事件被觸發即可

  - 老版本IE瀏覽器使用attachEvent添加onreadystatechange和onload來監聽,任何一個被觸發,並且onreadystatechange時document.readyState === "complete"即可。

  jQuery的處理也就是如此了

jQuery.ready.promise = function(){
  ...
  //標准瀏覽器支持DOMContentLoaded事件
  else if ( document.addEventListener ) { //綁定DOMContentLoaded事件和響應函數,響應函數會解決延時 document.addEventListener( "DOMContentLoaded", completed, false ); //回退到window.onload事件綁定,所有的瀏覽器都支持 window.addEventListener( "load", completed, false ); //如果是IE事件模型 } else { //確保在onload之前執行延時,可能時間比較遲,但是對於iframes來說比較安全 document.attachEvent( "onreadystatechange", completed ); //回退到window.onload事件綁定,所有的瀏覽器都支持 window.attachEvent( "onload", completed );
       ...   } }
//ready事件處理函數 completed = function( event ) { // readyState === "complete"在老版本IE上適用 if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { detach(); jQuery.ready(); } }

  

b.doScroll檢測文檔加載完成


  這是Diego Perini 發現的一種檢測IE是否加載完成的方式。詳細鏈接

  原理是當頁面 DOM 未加載完成時調用 doScroll 方法時會產生異常。那么不斷的取檢測異常是否發生就可以知道文檔有沒有加載完成。當沒有發生異常,表明文檔加載完成了。

                (function doScrollCheck() {
                    if ( !jQuery.isReady ) {
                        try {
                            // Use the trick by Diego Perini
                            // http://javascript.nwbox.com/IEContentLoaded/
                            top.doScroll("left");
                        } catch(e) {
                            return setTimeout( doScrollCheck, 50 );
                        }

                        //移除之前綁定的事件
                        detach();

                        //執行延遲
                        jQuery.ready();
                    }
                })();

 

 


免責聲明!

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



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