jQuery源碼 Ajax模塊分析

寫在前面:javascript

先講講ajax中的相關函數,而後結合函數功能來具體分析源代碼。java

相關函數:jquery

>>ajax全局事件處理程序ajax

.ajaxStart(handler) 註冊一個ajaxStart事件處理器。當一個Ajax請求開始,而且同時無其它未完成的Ajax請求時,jQuery觸發ajaxStart事件。
.ajaxSend(handler) 註冊一個ajaxSend事件處理器。當一個Ajax請求被髮送時觸發ajaxSend事件。
.ajaxSuccess(handler) 註冊一個ajaxSuccess事件處理器。當一個Ajax請求成功時觸發ajaxSuccess事件。
.ajaxError(handler) 註冊一個ajaxError事件處理器。當一個Ajax請求出錯時觸發ajaxError事件。
.ajaxComplete(handler) 註冊一個ajaxComplete事件處理器。當一個Ajax請求完成時觸發ajaxComplete事件。
.ajaxStop(handler) 註冊一個ajaxStop事件處理器。,當一個Ajax請求完成,而且同時無其它未完成的Ajax請求時觸發ajaxStop事件。

注意:json

這六個Ajax全局事件的處理函數都應該註冊在document上。api

   例如: $(document).ajaxSuccess(handler);跨域

ajax選項中的global是全局ajax事件的開關。若是global選項設置爲false,上面的全部ajax全局事件都不會被觸發。瀏覽器

特別注意的是ajaxStart和ajaxStop事件上面描述的文字的不一樣之處。緩存

>> Ajax的基本函數架構

jQuery.ajaxSetup()

jQuery.ajaxSetup(options) 設置Ajax默認的選項。

options對象包含用來配置ajax請求的key/value鍵值對。

函數直接擴展了jQuery.ajaxSetting這個對象,這個對象是Ajax請求的默認的配置對象,擴展後對之後的每一個Ajax請求都將產生影響。所以非特殊狀況不推薦擴展Ajax的默認選項。

Ajax源碼中的使用

//擴展jQuery.ajaxSetting默認選項集合
jQuery.ajaxSetup({
    accepts: {
        script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
    },
    contents: {
        script: /(?:java|ecma)script/
    },
    converters: {
        "text script": function( text ) {
            jQuery.globalEval( text );
            return text;
        }
    }
});

上面的代碼,擴展了jQuery.ajaxSetting中的三個默認屬性,accepts、contents、converters,這三個屬性對象添加對script數據類型的支持。後面介紹這三個選項的用途。

jQuery.ajaxPrefilter( )

jQuery.ajaxPrefilter([dataTypes,]handler)

在每一個ajax請求開始以前,對請求作前置處理。

dataTypes是包含一個或者多個空格分開的dataType的字符串。 用來限定前置處理應用的Ajax請求的範圍。 dataTypes參數可選,默認是」*」,當某個dataType的前置處理函數隊列執行完畢後,最終會執行」*」對應的處理函數隊列。

handler參數 function(options,originalOptions,jqXHR) 即具體的處理函數,其中options參數表明用戶選項集合即originalOptions和默認選項集合即jQuery.ajaxSetting綜合後的請求最終使用選項集合,originalOptions表明調用ajax函數時的用戶選項集合,jqXHR是jQuery封裝的XHR對象,包含相關的屬性和方法。

栗子: 在jQuery源碼中,Ajax模塊有兩處使用了這個函數。

// Handle cache's special case and global
//script類型請求的前置處理
//a.默認不使用瀏覽器緩存
//b.對於跨域請求:使用get方法,而且設置global爲false,即不觸發全局ajax對象。
jQuery.ajaxPrefilter( "script", function( s ) {
    if ( s.cache === undefined ) {
        s.cache = false;
    }
    if ( s.crossDomain ) {
        s.type = "GET";
        s.global = false;
    }
});

// Detect, normalize options and install callbacks for jsonp requests
//對json和jsonp類型ajax請求的前置處理
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
    //省略其它內容...
    
    return "script";
}

注意:

針對某個數據類型dataType,你能夠註冊多個處理函數。函數會依次執行。

處理函數能夠返回一個dataType字符串,此時jQuery不會繼續執行隊列中的其它後續處理函數,而是將此字符串添加到請求選項的dataTypes頭部,而且轉而執行此字符串所對應的前置處理程序。

例如上面的代碼中,在對json和jsonp的前置處理中,返回」script」,那麼script字符串會被添加到options.dataTypes頭部(options就是前面提到的請求最終使用的選項集合),而且會跳轉到執行」script」對應的前置處理程序。

jQuery.ajaxTransport( )

jQuery.ajaxTransport(dataType,handler)

dataType 表示請求的數據類型。

handler函數,function(options,originalOption,jqXHR) ,函數返回一個對象,這個表明請求此數據類型時,實際使用的完成傳輸行爲的對象。我把它稱做傳輸對象。傳輸對象應該包含兩個方法,send和abort。 jQuery內部會爲每一個對應此數據類型的Ajax請求建立這個傳輸對象。

調用過程就像下面這樣:

$.ajaxTransport( dataType, function( options, originalOptions, jqXHR ) {
  if( /* transportCanHandleRequest */ ) {
    return {
      send: function( headers, completeCallback ) {
        // Send code
      },
      abort: function() {
        // Abort code
      }
    };
  }
});

其中,send函數的參數

  • headers 對象 包含請求頭的各類設置
  • completeCallback 函數 當傳輸過程完成時,調用此函數來告訴Ajax傳輸過程結束。
  • completeCallback接受四個參數 ( status, statusText, responses, headers )
  • 其中responses是包含 dataType/value 的對象。例如像這樣的{ xml: XMLData, text: textData }

這個函數爲ajax請求帶來了極大的靈活性,你能夠定製本身的傳輸過程。例如,你能夠定製一個dataType爲」image」的ajax請求

$.ajaxTransport( "image", function( s ) {
  if ( s.type === "GET" && s.async ) {
    var image;
    return {
      send: function( _ , callback ) {
        image = new Image();
        function done( status ) {
          if ( image ) {
            var statusText = ( status === 200 ) ? "success" : "error",
              tmp = image;
            image = image.onreadystatechange = image.onerror = image.onload = null;
            callback( status, statusText, { image: tmp } );
          }
        }
        image.onreadystatechange = image.onload = function() {
          done( 200 );
        };
        image.onerror = function() {
          done( 404 );
        };
        image.src = s.url;
      },
      abort: function() {
        if ( image ) {
          image = image.onreadystatechange = image.onerror = image.onload = null;
        }
      }
    };
  }
});

注意到上面callback( status, statusText, { image: tmp } ); callback函數的response參數值是{image:tmp}, image對應數據類型。

jQuery的Ajax模塊源代碼中,有兩處調用了ajaxTransport函數。

一種用來生成是Ajax默認的傳輸對象。

jQuery.ajaxTransport(function( s ) {  
//建立"*"對應的transport,即默認處理全部請求的transport
//代碼省略
});

上面的ajaxTransport調用省略了dataType參數,此時建立的就是」*」對應的傳輸過程,即默認使用的傳輸過程。

另一種狀況,ajax對於跨域的」script」數據類型的請求,使用特殊的傳輸對象。

// Bind script tag hack transport
//請求script文件使用的傳輸對象。
jQuery.ajaxTransport( "script", function(s) {

    // This transport only deals with cross domain requests
    //只處理跨域的script數據類型
    //能夠看到跨域的script文件是經過HTML的script標籤請求並執行。
    if ( s.crossDomain ) {

        var script,
            head = document.head || jQuery("head")[0] || document.documentElement;

        return {

            send: function( _, callback ) {

                script = document.createElement("script");

                script.async = true;

                if ( s.scriptCharset ) {
                    script.charset = s.scriptCharset;
                }

                script.src = s.url;

                // Attach handlers for all browsers
                //isAbort參數在下面定義的abort方法中手動調用script.onload函數時設爲true
                //IE的 script 元素支持onreadystatechange事件,不支持onload事件。
                //FF的script 元素不支持onreadystatechange事件,只支持onload事件。
                script.onload = script.onreadystatechange = function( _, isAbort ) {
                    //isAbort時,作清除script的處理
                    //!script.readyState 說明是在FF下面,此時代表load完成
                    ///loaded|complete/.test( script.readyState )代表在IE下須要檢測到readyState爲loaded或者complete時,纔算load完成
                    if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {

                        // Handle memory leak in IE
                        script.onload = script.onreadystatechange = null;

                        // Remove the script
                        if ( script.parentNode ) {
                            script.parentNode.removeChild( script );
                        }

                        // Dereference the script
                        script = null;

                        // Callback if not abort
                        if ( !isAbort ) {
                            callback( 200, "success" );
                        }
                    }
                };

                // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
                // Use native DOM manipulation to avoid our domManip AJAX trickery
                head.insertBefore( script, head.firstChild );
            },

            abort: function() {
                if ( script ) {
                    script.onload( undefined, true );
                }
            }
        };
    }
});

注意:

與前面講的ajaxPrefilter類似,每種數據類型能夠定義多個傳輸函數。若是其中一個函數返回了傳輸對象,那麼就終止函數隊列的調用。若是具體數據類型未獲得傳輸對象,最後會調用「*」對應的傳輸函數隊列。

jQuery.ajax()

        放在單獨的一個篇文章裏

>> ajax相關的快捷方法

jQuery.post()

jQuery.get()

jQuery.getJSON()

jQuery.getScript()

.load()

     另起一片文章講。

>> Ajax源代碼的架構和流程分析

    另起一片文章講。

>>ajax返回jqXHR對象分析,關於Deferred對象

       另起一片文章講。

 

最後: 第一次寫,寫文章果真麻煩,感受內容量好大,一時半會兒寫不完,仍是分多個板塊來寫吧。先直接貼Ajax模塊的源代碼(帶註解)。

相關文章
相關標籤/搜索