jQuery源碼解讀3:.ajax()函數

1、從ajax調用出發

$.ajax({
    url:"http://www.microsoft.com",    //設置請求的url
    dataType:"json",   //設置數據返回格式爲json
    async:true,//設置請求是否異步,默認爲異步。
    data:{"id":"value"},    //設置發送的數據
    type:"GET",   //設置請求方式
    beforeSend:function(){
        //設置請求前的回調
    },
    success:function(req){
        //設置請求成功後的回調
    },
    complete:function(){
        //設置請求完成後的回調
    },
    error:function(){
        //設置請求出錯處理的回調
    }
});

從ajax標準的請求調用代碼中咱們看到傳入了一個參數,這個參數是一個對象。對象中定義了XMLHttpRequest對象所需的數據集合。javascript

2、萬變不離其宗:瞭解本質

咱們知道.ajax()是jQuery對XMLHttpRequest對象發送HTTP請求的一個js封裝接口,因此總歸要作一下幾部:建立XMLHttpRequest對象,而後open進行tcp連接,其次添加相關的頭部信息和定義回調函數等等設置,最後send給服務器並攜帶相關數據。java

xmlhttp = new XMLHttpRequest();
        xmlhttp.onreadystatechange=callback;
        xmlhttp.open("POST","test.do",true);
//        // 設置POST請求的請求頭
        xmlhttp.setRequestHeader("Content-Type"
            , "application/json");
        xmlhttp.send('password=123&username=mingzi');

3、ajax()在jQuery中哪裏定義

如圖所示,ajax定義在.extend()函數調用的惟一參數對象中,咱們前面解讀extend源碼的時候知道,若是extend函數中只有一個參數(對象)的時候,這個參數就是源對象,jQuery爲目標對象。這樣等效於在jQuery對象上擴展這個源對象的全部屬性,其中之一的ajax就被擴展到jQuery對象上,成爲jQuery靜態工具函數的其中一員。ajax

4、拆解.ajax()函數

1.  .ajax()方法執行的6個關鍵步驟:

1)構造完整的請求選項集,並修正選項。【預處理AJAX全部數據合併用戶定義的數據和默認數據】
2)構造jqXHR對象,並增長異步隊列的行爲。【http頭部數據】
3)構造回調函數done(status,nativeStatusText,responses,headers),響應完成以後被調用,負責轉換數據類型、執行回調函數、觸發全局事件。【回調函數模型,處理全部狀態的回調】
4)應用前置過濾器,繼續修正選項。【數據處理】
5)獲取請求發送器,並調用方法send(requestHeaders,done)發送請求。【建立XMLHttpRequest對象及open、send及回調處理等方法】
6)最後返回jqXHR對象。json

二、構造完整的請求選項集

1)傳進來的參數對象預處理數組

A. 若是第一個參數是對象類型,那option 就直接等於 第一個參數 url。而後消滅url = undefined。瀏覽器

B. 經過與一個空對象()進行或運算,強制option爲一個對象!服務器

ajax: function( url, options ) {
		// If url is an object, simulate pre-1.5 signature
		if ( typeof url === "object" ) {
			options = url;
			url = undefined;
		}
		// Force options to be an object
		options = options || {};
        s = jQuery.ajaxSetup( {}, options ),
}

2) 建立最終選項對象(XMLHttpRequest所需的數據集):將傳進來的對象與默認選項對象進行深度合併。網絡

A. jQuery.ajaxSetup — ajaxExtend() —— jQuery.ajaxSettings——jQuery.ajaxSettings.flatOptionsapp

B. 簡而言之是經過以上的幾個函數調用將默認選項對象jQuery.ajaxSettings和用戶自定義的ajax參數(選項對象)經過ajaxExtend進行深度合併(除了url和context不深度外),獲得一個最終的選項對象s。以下:cors

3. 構造jqXHR對象

jqXHR對象是瀏覽器原生XMLHttpRequest對象的超集,當請求發送器不是XMLHttpRequest時,jqXHR對象會盡量地模擬XMLHttpRequest的功能。而且,jqXHR對象還具有異步隊列的方法和行爲。爲了兼容XMLHttpRequest,jqXHR對象暴露了如下屬性和方法:
❑readyState:表示當前jqXHR對象的狀態。
❑status:響應的HTTP狀態碼。
❑statusText:響應的HTTP狀態描述。
❑responseText、responseXML:響應的文本內容、XML文檔。
❑setRequestHeader(name,value):設置請求頭 […]

❑getAllResponseHeaders():獲取響應頭字符串。
❑getResponseHeader(key):獲取指定名稱的響應頭的值。
❑overrideMimeType(type):用於覆蓋MIME類型。
❑abort(statusText):取消本次請求。

4. done構造函數!

1)在.ajax()函數中根據須要直接調用done;

2)傳入發送器的send()函數當send的回調函數對發送數據完成後回調執行。

transport.send( requestHeaders, done );
//傳入整個done回調函數放到transport.send(參數中
send: function( headers, complete ) {

//定義發送器send中的回調函數Callback
				callback = function( type ) {
					return function() {
						if ( callback ) {
							if ( type === "abort" ) {
								xhr.abort();
							} else if ( type === "error" ) {
									complete( 0, "error" );
							} else {
								complete(
									xhrSuccessStatus[ xhr.status ] || xhr.status,
									xhr.statusText,
									( xhr.responseType || "text" ) !== "text"  ||
									typeof xhr.responseText !== "string" ?
										{ binary: xhr.response } :
										{ text: xhr.responseText },
									xhr.getAllResponseHeaders()

				// Listen to events
//啓動回調函數的監聽
				xhr.onload = callback();

五、數據處理:應用前置過濾器,繼續修正選項

1)常規的:

s.url = ( ( url || s.url || location.href ) + "" )
			.replace( rprotocol, location.protocol + "//" );

		// Alias method option to type as per ticket #12004
		s.type = options.method || options.type || s.method || s.type;

2)應用前置過濾器繼續修正選項對象

prefilters = {},//空過濾器

ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),//向對象prefilters中添加前置過濾器

inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );//從對象prefilters中找到數據類型對應的前置過濾器數組,逐個執行

6. 發送器

1)咱們能夠從如下代碼中看到transports發送器中含有XMLHttpRequest對象,及open建立網絡連接、send()發送和abort()取消發送方法,還有執行回調函數complete 。

2)一次send的執行:transport.send( requestHeaders, done ); done是一個回調函數模型。能夠執行各類http狀態的回調!

transports = {},

ajaxTransport: addToPrefiltersOrTransports( transports ),

//經過inspectPrefiltersOrTransports獲取發送器
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );

//發送器實體
jQuery.ajaxTransport( function( options ) {
	var callback, errorCallback;

	// Cross domain only allowed if supported through XMLHttpRequest
	if ( support.cors || xhrSupported && !options.crossDomain ) {
		return {
			send: function( headers, complete ) {
//構造XMLHttpRequest對象放在發送器裏
				var i,xhr = options.xhr();
				xhr.open(options.type,options.url,options.async,options.username,options.password);
				// Set headers
				for ( i in headers ) {
					xhr.setRequestHeader( i, headers[ i ] );
				}
				// Callback
				callback = function( type ) {
					return function() {
						if ( callback ) {
							callback = errorCallback = xhr.onload =
								xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
							if ( type === "abort" ) {
								xhr.abort();
							} else if ( type === "error" ) {
									complete(
										xhr.status,
										xhr.statusText
									);
								}
							} else {
								complete(
									xhrSuccessStatus[ xhr.status ] || xhr.status,
									xhr.statusText,
									( xhr.responseType || "text" ) !== "text"  ||
									typeof xhr.responseText !== "string" ?
										{ binary: xhr.response } :
										{ text: xhr.responseText },
									xhr.getAllResponseHeaders()
								);
							}
						}
					};
				};
				xhr.onload = callback();
			},

			abort: function() {
				if ( callback ) {
					callback();
				}
			}
		};
	}
} );

//構造XMLHttpRequest對象放在發送器裏
options.xhr() = jQuery.ajaxSettings.xhr = function() {
	try {
		return new window.XMLHttpRequest();
	} catch ( e ) {}
};

5、總結

相關文章
相關標籤/搜索