針對獲取到location.href的兼容代碼:
- try {
- ajaxLocation = location.href;
- } catch( e ) {
- // Use the href attribute of an A element
- // since IE will modify it given document.location
- ajaxLocation = document.createElement( "a" );
- ajaxLocation.href = "";
- ajaxLocation = ajaxLocation.href;
- }
note:如果通過location.href獲取地址出錯,那么我們就通過創建A標簽,然后獲取該標簽的href!在IE中可以打印主機名,如"http://locahost:8080/"
關於去除URL中的hash值,同時兼容IE7,如果沒有協議字段我們要手動添加:
- var ajaxLocation="http://localhost:8080/qinl/a.action?#23"
- var rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/;
- var rhash = /#.*$/;
- //匹配開頭的"//"字段
- var rprotocol = /^\/\//;
- //獲取前面的協議字段,如"http:","file:"等
- var ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
- //第一個replace去掉用hash值,第二個replace表示如果去掉hash值以后開頭已經是//那么也要進行相應的處理
- var result=ajaxLocation.replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
匹配是否跨域請求的部分:
- //測試代碼1:
- var rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/; //打印[http://localhost:8080,http:,localhost,8080]
- alert(rurl.exec("http://localhost:8080/qinl/xx.action"));
- //測試代碼2:
- //http://www.365mini.com/diy.php?f=jquery_ajax-demo
- var ajaxLocation=location.href;
- var ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
- //打印[http://www.365mini.com,http:,www.365mini.com,]
- alert(ajaxLocParts);
首先來一段精簡版的$.ajax方法:也就是其中的原理
- var completeDeferred = jQuery.Callbacks("once memory");
- var dfd=new $.Deferred();
- var jqXHR={
- }
- //jqXHR有了promise所有方法,但是修改狀態還是要靠Deferred對象!
- //同時為這個jqXHR封裝一個Callbacks對象,調用complete就想相當於向其中添加
- //回調函數,然后要觸發他就直接調用fireWith才行!
- dfd.promise(jqXHR).complete=completeDeferred.add;
- var f1=function()
- {
- alert("f1");
- }
- //為done和complete添加回調函數
- jqXHR.done(f1).complete(f1);
- //調用fire觸發所有的complete添加的回調
- completeDeferred.fire();
- //觸發Deferred對象的所有的done集合中函數,記住這里
- //不能是dfd調用,因為他沒有resolve方法不能改變狀態!
- dfd.resolve();
ajax源碼分析:
- ajax: function( url, options ) {
- //ajax方法參數調整,如果url是object,這是我們一般的調用方式
- // If url is an object, simulate pre-1.5 signature
- if ( typeof url === "object" ) {
- options = url;
- url = undefined;
- }
- //option是一個對象
- // Force options to be an object
- options = options || {};
- var // Cross-domain detection vars
- parts,
- // Loop variable
- i,
- // URL without anti-cache param
- cacheURL,
- // Response headers as string
- responseHeadersString,
- // timeout handle
- timeoutTimer,
- // To know if global events are to be dispatched
- fireGlobals,
- transport,
- // Response headers
- responseHeaders,
- // Create the final options object
- s = jQuery.ajaxSetup( {}, options ),
- // Callbacks context
- //設置context,如果沒有context那么就是返回的最終的options=ajaxSettings+options(用戶調用ajax方法時候傳送的option)
- callbackContext = s.context || s,
- //如果傳入的對象有context,同時context是DOM對象或者是jQuery對象,那么把該DOM對象封裝為jQuery對象
- //如果不滿足也就是沒有context或者context不是DOM對象和jQuery對象,那么globalEventContext就是jQuery.event對象!
- // Context for global events is callbackContext if it is a DOM node or jQuery collection
- globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
- jQuery( callbackContext ) :
- jQuery.event,
- //創建Deferred對象
- // Deferreds
- deferred = jQuery.Deferred(),
- //創建Callbacks對象
- completeDeferred = jQuery.Callbacks("once memory"),
- //獲取最終options的statusCode參數,默認是空對象!
- // Status-dependent callbacks
- statusCode = s.statusCode || {},
- // Headers (they are sent all at once)
- requestHeaders = {},
- requestHeadersNames = {},
- // The jqXHR state
- state = 0,
- // Default abort message
- strAbort = "canceled",
- //創建一個偽的xhr對象,該對象有readyState,getResponseHeader,getAllResponseHeaders,setRequestHeader
- //overrideMimeType,statusCode,abort方法和屬性!
- // Fake xhr
- jqXHR = {
- readyState: 0,
- // Builds headers hashtable if needed
- getResponseHeader: function( key ) {
- var match;
- //狀態是2的時候才能獲取數據
- if ( state === 2 ) {
- if ( !responseHeaders ) {
- responseHeaders = {};
- //rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
- //responseHeaders的鍵名就是第一個捕獲組的數據,第二個鍵值就是第二個捕獲組數據!
- while ( (match = rheaders.exec( responseHeadersString )) ) {
- responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
- }
- }
- //返回這個key對應的鍵值!
- match = responseHeaders[ key.toLowerCase() ];
- }
- return match == null ? null : match;
- },
- // Raw string
- //如果狀態是2,那么就是responseHeadersString
- getAllResponseHeaders: function() {
- return state === 2 ? responseHeadersString : null;
- },
- // Caches the header
- //設置HTTP請求頭的時候,頭是小寫的
- setRequestHeader: function( name, value ) {
- var lname = name.toLowerCase();
- //如果state為0那么就緩存頭,把結果放入requestHeaders中!但是要提前查找requestHeadersNames
- if ( !state ) {
- name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
- requestHeaders[ name ] = value;
- }
- return this;
- },
- // Overrides response content-type header
- //如果state=0那么可以覆蓋這個mimetype!
- overrideMimeType: function( type ) {
- if ( !state ) {
- s.mimeType = type;
- }
- return this;
- },
- // Status-dependent callbacks
- statusCode: function( map ) {
- var code;
- if ( map ) {
- if ( state < 2 ) {
- for ( code in map ) {
- // Lazy-add the new callback in a way that preserves old ones
- statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
- }
- } else {
- // Execute the appropriate callbacks
- jqXHR.always( map[ jqXHR.status ] );
- }
- }
- return this;
- },
- // Cancel the request
- //取消請求
- abort: function( statusText ) {
- var finalText = statusText || strAbort;
- if ( transport ) {
- transport.abort( finalText );
- }
- done( 0, finalText );
- return this;
- }
- };
- // Attach deferreds
- //讓jqXHR具有promise的所有的屬性和方法!不包括狀態改變的方法,如resollveWith等
- //同時jqXHR的complete對應於completeDeferred的add方法,但是該jqXHR中也封裝了三個Callbacks對象
- //但是這里沒有用內部的Callbacks對象,而是采用一個新的Callbacks對象
- //completeDeferred = jQuery.Callbacks("once memory"),
- deferred.promise( jqXHR ).complete = completeDeferred.add;
- //success調用的promise對象內置的done方法對應於的Callbacks對象
- jqXHR.success = jqXHR.done;
- //error方法調用的promise對象內置的fail方法對應的Callbacks對象!
- //注意:這個內置的promise對象的progress方法對應的Callbacks對象沒有用到!
- jqXHR.error = jqXHR.fail;
- // Remove hash character (#7531: and string promotion)
- // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
- // Handle falsy url in the settings object (#10093: consistency with old signature)
- // We also use the url parameter if available
- s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
- //type就是get或者post。這個方式可以通過用戶傳入的對象的method或者type或者最終的對象的method或者type獲取!
- // Alias method option to type as per ticket #12004
- s.type = options.method || options.type || s.method || s.type;
- // Extract dataTypes list
- //取出dataType兩邊的空格,同時通過空格進行分組得到一個數組!dataType="html"
- s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
- //如果沒有crossDomain對象
- // A cross-domain request is in order when we have a protocol:host:port mismatch
- if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() );
- //如果在同一個域名里面那么這里的判斷都是false,結果就是crossDomain為false
- //如果不再同一個域名里面,那么這里的判斷都是true,結果就是crossDomain為true!
- s.crossDomain = !!( parts &&
- ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
- ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
- ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
- );
- }
- //如果存在data同時存在processData同時data不是string!
- //traditional是為了兼容jQuery<1.3.2行為的!
- // Convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" ) {
- s.data = jQuery.param( s.data, s.traditional );
- }
- // Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
- //如果在預過濾器中已經終止了請求,那么直接返回jqXHR對象!
- // If request was aborted inside a prefilter, stop there
- if ( state === 2 ) {
- return jqXHR;
- }
- // We can fire global events as of now if asked to
- // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
- //如果是global參數,那么我們直接trigger事件ajaxStart!
- fireGlobals = jQuery.event && s.global;
- // Watch for a new set of requests
- if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger("ajaxStart");
- }
- // Uppercase the type
- //把type變成大寫
- s.type = s.type.toUpperCase();
- // Determine if request has content
- //rnoContent = /^(?:GET|HEAD)$/
- //也就是如果沒有指定type也就是請求方式!
- s.hasContent = !rnoContent.test( s.type );
- // Save the URL in case we're toying with the If-Modified-Since
- // and/or If-None-Match header later on
- //獲取url參數!
- cacheURL = s.url;
- // More options handling for requests with no content
- //如果指定了請求方式,如get,post等!
- if ( !s.hasContent ) {
- //沒有指定請求方式的時候有傳遞數據!
- // If data is available, append data to url
- if ( s.data ) {
- //var rquery = (/\?/);
- //如果url后面有問號,那么直接把參數綁定到問號后面就可以了!否則添加問號在綁定!
- //同時刪除數據!
- cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
- // #9682: remove data so that it's not used in an eventual retry
- delete s.data;
- }
- // Add anti-cache in url if needed
- //如果指定了cache為false表示不能進行數據緩存,那么會在url后面添加一個當前時間!
- if ( s.cache === false ) {
- s.url = rts.test( cacheURL ) ?
- // If there is already a '_' parameter, set its value
- //var nonce = jQuery.now();
- cacheURL.replace( rts, "$1_=" + nonce++ ) :
- // Otherwise add one to the end
- cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
- }
- }
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- //如果添加了ifModified頭
- //var lastModified={}
- if ( s.ifModified ) {
- //如果lastModified保存了這個cacheURL也就是這個URL有緩存了!那么直接添加頭If-Modified-Since數據為
- //jQuery.lastModified[ cacheURL ]獲取到的數據!
- if ( jQuery.lastModified[ cacheURL ] ) {
- jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
- }
- //如果在etag: {}中保存了這個URL
- //那么添加If-None-Match,因為Etag和if-None-Match是一對,Last-Modified和If-Modified-Since是一對!
- if ( jQuery.etag[ cacheURL ] ) {
- jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
- }
- }
- // Set the correct header, if data is being sent
- //如果有數據傳送,同時也指定了get,post方法,同時contentType也指定!
- //那么添加一個頭Content-Type!
- if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
- jqXHR.setRequestHeader( "Content-Type", s.contentType );
- }
- // Set the Accepts header for the server, depending on the dataType
- //同時添加請求頭Accept
- //(1)如果指定了dataType,同時accepts中dataType存在,也就是必須是指定的data[type]
- jqXHR.setRequestHeader(
- "Accept",
- s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
- // allTypes = "*/".concat("*");
- //如果支持的數據類型是內置的類型,那么獲取內置的值,如text獲取的就是"text/plain"
- //同時dataTypes[0]不是"*",那么我們加上一個逗號,同時加上后面剩余的部分!
- /*
- var allTypes = "*/".concat("*");
- //打印
- //alert(allTypes);
- //最后的格式就是:text/html,*/*;q=0.01
- //如果傳入的dataType就是*,那么最后的結果就是"*/*"
- s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
- s.accepts[ "*" ]
- );
- // Check for headers option
- //如果還定義了headers選項,那么會被逐個發送到服務器端!
- for ( i in s.headers ) {
- jqXHR.setRequestHeader( i, s.headers[ i ] );
- }
- // Allow custom headers/mimetypes and early abort
- //如果指定了beforeSend,同時beforeSend的函數調用的結果是false或者state是2,那么取消這次請求
- //beforeSend中傳入的參數為callbackContext = s.context || s也就是最終對象的context參數為上下文
- //第一個參數是XHR對象,第二個參數是最終的options對象!
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
- // Abort if not done already and return
- return jqXHR.abort();
- }
- // aborting is no longer a cancellation
- strAbort = "abort";
- // Install callbacks on deferreds
- //往jqXHR["success"]和jqXHR["error"],jqXHR["complete"]中添加回調函數
- //回調函數就是通過最終options對象獲取到的success,error,complete函數!
- for ( i in { success: 1, error: 1, complete: 1 } ) {
- jqXHR[ i ]( s[ i ] );
- }
- // Get transport
- //傳入的參數是transports對象!這個函數里面會判斷是否傳入了transports
- transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
- // If no transport, we auto-abort
- if ( !transport ) {
- done( -1, "No Transport" );
- } else {
- //如果有transport那么readyState就是1,表示 (載入)已調用send()方法,正在發送請求,也就是請求的發送是在
- //inspectPrefiltersOrTransports里面完成的!
- jqXHR.readyState = 1;
- // Send global event
- //指示是否觸發全局Ajax事件。將該值設為false將阻止全局事件處理函數被觸發
- //fireGlobals = jQuery.event && s.global;
- //如果是表示全局ajax事件,那么我們要調用ajaxSend方法!同時為這個方法傳入參數jqXHR和最終option!
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
- }
- // Timeout
- //如果指定了async同時timeout>0表示指定了隔多少秒就放棄
- //一個超時調用,超時直接調用abort方法!
- if ( s.async && s.timeout > 0 ) {
- timeoutTimer = setTimeout(function() {
- jqXHR.abort("timeout");
- }, s.timeout );
- }
- //如果有transport,那么調用send方法!
- try {
- state = 1;
- transport.send( requestHeaders, done );
- } catch ( e ) {
- // Propagate exception as error if not done
- if ( state < 2 ) {
- done( -1, e );
- // Simply rethrow otherwise
- } else {
- throw e;
- }
- }
- }
總結:
(1)調用 jQuery.ajaxSetup( {}, options )讓最終options具有jQuery內置的所有的屬性,同時也包括用戶調用ajax方法的時候傳入的所有的屬性和方法!
(2)創建jqXHR對象,讓該對象具有Deferred的所有屬性和方法,該Deferred對象可以綁定用戶的success和error方法。但是用戶傳入的compelte方法表示任何情況下都會調用,我們就引入了一個Callbacks對象,把complete回調函數存入該Callback中(用fireWith調用)
(3)對URL處理,取出hash加上協議名稱,為type賦值,也就是Get/Post方法(用戶可以通過method或者type傳入該方法);指定dataTypes說明用戶需要要的數據類型(用戶通過dataType傳入);如果用戶沒有明確指定crossDomain,那么自己判斷,如果用戶傳入的URL也就是訪問的URL和當前的location.href不相同(包括協議名稱,主機名,端口號等),那么直接把crossDomain設置為true;如果傳入了數據,也就是data那么通過 jQuery.param方法把這個數據序列化;
(4)上述步驟完成以后,我們就調用inspectPrefiltersOrTransports,這個方法傳入了prefilters,表示對prefilters中所有的預處理函數進行檢測,該方法可以修改前面所有的參數,當然也可以添加新的信息!(這里是prefilters)
(5)如果用戶傳入了global參數,那么我們在這個步驟執行"ajaxStart"事件
globalBoolean類型
默認值:true
。指示是否觸發全局Ajax事件。將該值設為false
將阻止全局事件處理函數被觸發,例如ajaxStart()和ajaxStop()。它可以用來控制各種Ajax事件。
(6)如果指定了get/head請求,那么如果有數據那么把數據綁定到URL后面(同時保存這個URL以便緩存URL)。同時如果是指定了get/head時候還明確指定了不能緩存數據,那么我們把緩存的URL后面添加一個隨機數,隨機數是當前時間!(一開始設定了緩存URL是用戶傳入的ur,get/head請求等都會對URL修改)
(7)如果用戶指定了ifModified,表示只有數據改變時候才發送請求。如果這個URL已經訪問過了,那么我們取出訪問該URL時候服務器給的etag和if-none-match標簽,並且把他們通過"If-None-Match和If-Modified-Since形式發送給服務器端,讓服務器端去判斷數據有沒有改變。這兩個頭是在done方法中,也就是成功回調時候設置的!
ifModifiedBoolean類型
默認值:false
。允許當前請求僅在服務器數據改變時獲取新數據(如未更改,瀏覽器從緩存中獲取數據)。它使用HTTP頭信息Last-Modified
來判斷。從jQuery 1.4開始,他也會檢查服務器指定的'etag'來確定數據是否已被修改。
(8)設置數據類型content-type,把content-type的頭添加到jqXHR對象上
contentTypeString類型
默認值:'application/x-www-form-urlencoded; charset=UTF-8'。使用指定的內容編碼類型將數據發送給服務器。W3C的XMLHttpRequest規范規定charset始終是UTF-8,你如果將其改為其他字符集,也無法強制瀏覽器改字符編碼。
(9)設置accept頭,告訴服務器瀏覽器能夠接受的數據類型
acceptsObject類型
默認值:取決於dataType
屬性。發送的內容類型請求頭,用於告訴服務器——瀏覽器可以接收服務器返回何種類型的響應。如果傳入的是"*"結果就是"*/*",否則就是如格式"text/html,*/*;q=0.01"
(10)設置用戶通過headers傳入的HTTP頭
headersObject類型1.5 新增
默認值:{}
。以對象形式指定附加的請求頭信息。請求頭X-Requested-With: XMLHttpRequest
將始終被添加,當然你也可以在此處修改默認的XMLHttpRequest值。headers
中的值可以覆蓋beforeSend
回調函數中設置的請求頭(意即beforeSend先被調用)。
(11)調用beforeSend
beforeSendFunction類型
指定在請求發送前需要執行的回調函數。該函數還有兩個參數:其一是jqXHR
對象,其二是當前settings
對象。這是一個Ajax事件,如果該函數返回false
,將取消本次ajax請求。
(12)這一步才把我們傳入的success,error,compelete放入相應的Deferred對象和Callback對象里面,以備回調!
(13)這一步是重點:調用transport里面所有的函數集合。函數調用的返回結果是一個對象,該對象有send和abort方法。調用send方法就是真正的向服務器發送數據,如果沒有得到transport對象那么表示請求失敗。如果得到了這個對象,那么我們把readyState設置為1,然后調用send方法,但是調用send方法之前我們要調用ajaxSend方法!在send方法調用時候transport.send( requestHeaders, done );我們傳入了回調函數done方法,該方法處理了回調的邏輯!
我們看看下面的done方法的處理邏輯:
- function done( status, nativeStatusText, responses, headers ) {
- var isSuccess, success, error, response, modified,
- statusText = nativeStatusText;
- // Called once
- //如果state是2,那么直接返回!
- if ( state === 2 ) {
- return;
- }
- // State is "done" now
- //state設置為2表示不會再次執行了!
- state = 2;
- // Clear timeout if it exists
- //如果timeoutTimer存在,那么直接清除!
- if ( timeoutTimer ) {
- clearTimeout( timeoutTimer );
- }
- // Dereference transport for early garbage collection
- // (no matter how long the jqXHR object will be used)
- transport = undefined;
- // Cache response headers
- //獲取response的頭部信息,默認是空!
- responseHeadersString = headers || "";
- // Set readyState
- //如果status>0那么把readyState設置為4!
- jqXHR.readyState = status > 0 ? 4 : 0;
- // Determine if successful
- //如果status在指定的區間內那么表示成功!
- isSuccess = status >= 200 && status < 300 || status === 304;
- // Get response data
- //如果done方法有responses那么對他進行處理!
- if ( responses ) {
- response = ajaxHandleResponses( s, jqXHR, responses );
- }
- // Convert no matter what (that way responseXXX fields are always set)
- response = ajaxConvert( s, response, jqXHR, isSuccess );
- // If successful, handle type chaining
- if ( isSuccess ) {
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- //如果ifModified存在,那么就要設置If-Modified-Since和If-None-Match頭!
- if ( s.ifModified ) {
- modified = jqXHR.getResponseHeader("Last-Modified");
- if ( modified ) {
- jQuery.lastModified[ cacheURL ] = modified;
- }
- modified = jqXHR.getResponseHeader("etag");
- if ( modified ) {
- jQuery.etag[ cacheURL ] = modified;
- }
- }
- // if no content
- //204表示沒有數據,這時候頁面就不需要跳轉!還是停留在當前頁面!
- if ( status === 204 || s.type === "HEAD" ) {
- statusText = "nocontent";
- //如果是304那么表示沒有修改內容!
- // if not modified
- } else if ( status === 304 ) {
- statusText = "notmodified";
- //如果有數據,那么我們獲取到數據!
- // If we have data, let's convert it
- } else {
- statusText = response.state;
- success = response.data;
- error = response.error;
- isSuccess = !error;
- }
- } else {
- //這里的else表示請求失敗!我們從statusText獲取到錯誤的信息,然后對statusText進行處理!
- // We extract error from statusText
- // then normalize statusText and status for non-aborts
- error = statusText;
- if ( status || !statusText ) {
- statusText = "error";
- if ( status < 0 ) {
- status = 0;
- }
- }
- }
- //為jqXHR設置數據
- // Set data for the fake xhr object
- jqXHR.status = status;
- jqXHR.statusText = ( nativeStatusText || statusText ) + "";
- // Success/Error
- if ( isSuccess ) {
- //如果成功了請求,那么我們傳入的Context是callbackContext,傳入的數據是response.data
- //response.status和jqXHR對象
- deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
- } else {
- deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
- }
- // Status-dependent callbacks
- jqXHR.statusCode( statusCode );
- statusCode = undefined;
- //如果是全局執行
- if ( fireGlobals ) {
- globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
- [ jqXHR, s, isSuccess ? success : error ] );
- }
- // Complete
- //這個對象添加的所有函數執行,表示完成,不是成功,失敗,而是complelte表示不管成功與否都是會執行的!
- //而且只會執行一次!
- completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
- if ( fireGlobals ) {
- //globalEventContext也就是最終options的事件,觸發事件ajaxComplete!
- globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
- // Handle the global AJAX counter
- //如果全局的ajax計數器已經是0了,那么就會觸發ajaxStrop事件!
- if ( !( --jQuery.active ) ) {
- jQuery.event.trigger("ajaxStop");
- }
- }
- }
- return jqXHR;
- }
- );
note:
(1)state在send調用之前為1,在done方法調用的時候設置為2,默認為0.所以2表示已經回調成功了,1表示send方法已經調用但是還沒有回調。
(2)調用順序是ajaxStart,ajaxSend,ajaxSuccess/ajaxError,ajaxComplete,ajaxStop這就是全局事件的調用順序!
(3)在done方法中通過resolveWith,rejectWith來觸發success,error事件,通過fireWith來觸發compelete事件
(4)返回真實的服務器端數據,如responseText服務器端的數據!ajaxHandleResponses作用:把服務器端返回的數據封裝到jqXHR對象上面,形成jqXHR["responseText"]=xhr.responseText這種類型!同時把responses中的相應的數據取出來。因為responses={"text":xhr.responseText}是這種類型,這個方法最后形成的返回數據為responses["text"]=xhr.responseText,也就是得到服務器端的數據!
(5)ajaxConverter作用:左后返回一個對象,該對象有state和data屬性,如{state:"success",data:response}其中response就是上面提到的經過處理的服務器端返回的數據!
(6)如果指定了global表示支持全局事件的調用,那么在jQuery.active的值為0的時候調用一次ajaxStart,調用完成以后讓active自增,在調用ajaxStop之前首先讓active自減,如果是0才會調用ajaxStop!