jquery中的$.ajax()的源碼分析

針對獲取到location.href的兼容代碼:javascript

 

[javascript]  view plain  copy
 
  1. try {  
  2. ajaxLocation = location.href;  
  3. catch( e ) {  
  4.     // Use the href attribute of an A element  
  5.     // since IE will modify it given document.location  
  6.     ajaxLocation = document.createElement( "a" );  
  7.     ajaxLocation.href = "";  
  8.     ajaxLocation = ajaxLocation.href;  
  9. }  

note:若是經過location.href獲取地址出錯,那麼咱們就經過建立A標籤,而後獲取該標籤的href!在IE中能夠打印主機名,如"http://locahost:8080/"
關於去除URL中的hash值,同時兼容IE7,若是沒有協議字段咱們要手動添加:php

 

 

[javascript]  view plain  copy
 
  1. var ajaxLocation="http://localhost:8080/qinl/a.action?#23"  
  2. var rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/;  
  3. var rhash = /#.*$/;  
  4. //匹配開頭的"//"字段  
  5. var rprotocol = /^\/\//;  
  6. //獲取前面的協議字段,如"http:","file:"等  
  7. var ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];  
  8. //第一個replace去掉用hash值,第二個replace表示若是去掉hash值之後開頭已是//那麼也要進行相應的處理  
  9. var result=ajaxLocation.replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );  

匹配是否跨域請求的部分:html

 

 

[javascript]  view plain  copy
 
  1. //測試代碼1:  
  2. var rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/; //打印[http://localhost:8080,http:,localhost,8080]  
  3. alert(rurl.exec("http://localhost:8080/qinl/xx.action"));  
  4. //測試代碼2:  
  5. //http://www.365mini.com/diy.php?f=jquery_ajax-demo  
  6. var ajaxLocation=location.href;  
  7. var ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];  
  8. //打印[http://www.365mini.com,http:,www.365mini.com,]  
  9. alert(ajaxLocParts);  

首先來一段精簡版的$.ajax方法:也就是其中的原理java

 

[javascript]  view plain  copy
 
  1. var completeDeferred = jQuery.Callbacks("once memory");  
  2. var dfd=new $.Deferred();  
  3. var jqXHR={  
  4. }  
  5. //jqXHR有了promise全部方法,可是修改狀態仍是要靠Deferred對象!  
  6. //同時爲這個jqXHR封裝一個Callbacks對象,調用complete就想至關於向其中添加  
  7. //回調函數,而後要觸發他就直接調用fireWith才行!  
  8. dfd.promise(jqXHR).complete=completeDeferred.add;  
  9. var f1=function()  
  10. {  
  11.     alert("f1");  
  12. }  
  13. //爲done和complete添加回調函數  
  14. jqXHR.done(f1).complete(f1);  
  15. //調用fire觸發全部的complete添加的回調  
  16. completeDeferred.fire();  
  17. //觸發Deferred對象的全部的done集合中函數,記住這裏  
  18. //不能是dfd調用,由於他沒有resolve方法不能改變狀態!  
  19. dfd.resolve();  

ajax源碼分析:node

 

[javascript]  view plain  copy
 
  1. ajax: function( url, options ) {  
  2.          //ajax方法參數調整,若是url是object,這是咱們通常的調用方式  
  3.         // If url is an object, simulate pre-1.5 signature  
  4.         if ( typeof url === "object" ) {  
  5.             options = url;  
  6.             url = undefined;  
  7.         }  
  8.               //option是一個對象  
  9.         // Force options to be an object  
  10.         options = options || {};  
  11.         var // Cross-domain detection vars  
  12.             parts,  
  13.             // Loop variable  
  14.             i,  
  15.             // URL without anti-cache param  
  16.             cacheURL,  
  17.             // Response headers as string  
  18.             responseHeadersString,  
  19.             // timeout handle  
  20.             timeoutTimer,  
  21.             // To know if global events are to be dispatched  
  22.             fireGlobals,  
  23.             transport,  
  24.             // Response headers  
  25.             responseHeaders,  
  26.             // Create the final options object  
  27.             s = jQuery.ajaxSetup( {}, options ),  
  28.             // Callbacks context  
  29.             //設置context,若是沒有context那麼就是返回的最終的options=ajaxSettings+options(用戶調用ajax方法時候傳送的option)  
  30.             callbackContext = s.context || s,  
  31.             //若是傳入的對象有context,同時context是DOM對象或者是jQuery對象,那麼把該DOM對象封裝爲jQuery對象  
  32.             //若是不知足也就是沒有context或者context不是DOM對象和jQuery對象,那麼globalEventContext就是jQuery.event對象!  
  33.             // Context for global events is callbackContext if it is a DOM node or jQuery collection  
  34.             globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?  
  35.                 jQuery( callbackContext ) :  
  36.                 jQuery.event,  
  37.             //建立Deferred對象  
  38.             // Deferreds  
  39.             deferred = jQuery.Deferred(),  
  40.             //建立Callbacks對象  
  41.             completeDeferred = jQuery.Callbacks("once memory"),  
  42.             //獲取最終options的statusCode參數,默認是空對象!  
  43.             // Status-dependent callbacks  
  44.             statusCode = s.statusCode || {},  
  45.             // Headers (they are sent all at once)  
  46.             requestHeaders = {},  
  47.             requestHeadersNames = {},  
  48.             // The jqXHR state  
  49.             state = 0,  
  50.             // Default abort message  
  51.             strAbort = "canceled",  
  52.             //建立一個僞的xhr對象,該對象有readyState,getResponseHeader,getAllResponseHeaders,setRequestHeader  
  53.             //overrideMimeType,statusCode,abort方法和屬性!  
  54.             // Fake xhr  
  55.             jqXHR = {  
  56.                 readyState: 0,  
  57.                 // Builds headers hashtable if needed  
  58.                 getResponseHeader: function( key ) {  
  59.                     var match;  
  60.                     //狀態是2的時候才能獲取數據  
  61.                     if ( state === 2 ) {  
  62.                         if ( !responseHeaders ) {  
  63.                             responseHeaders = {};  
  64.                             //rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL  
  65.                             //responseHeaders的鍵名就是第一個捕獲組的數據,第二個鍵值就是第二個捕獲組數據!  
  66.                             while ( (match = rheaders.exec( responseHeadersString )) ) {  
  67.                                 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];  
  68.                             }  
  69.                         }  
  70.                         //返回這個key對應的鍵值!  
  71.                         match = responseHeaders[ key.toLowerCase() ];  
  72.                     }  
  73.                     return match == null ? null : match;  
  74.                 },  
  75.   
  76.                 // Raw string  
  77.                 //若是狀態是2,那麼就是responseHeadersString  
  78.                 getAllResponseHeaders: function() {  
  79.                     return state === 2 ? responseHeadersString : null;  
  80.                 },  
  81.   
  82.                 // Caches the header  
  83.                 //設置HTTP請求頭的時候,頭是小寫的  
  84.                 setRequestHeader: function( name, value ) {  
  85.                     var lname = name.toLowerCase();  
  86.                     //若是state爲0那麼就緩存頭,把結果放入requestHeaders中!可是要提早查找requestHeadersNames  
  87.                     if ( !state ) {  
  88.                         name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;  
  89.                         requestHeaders[ name ] = value;  
  90.                     }  
  91.                     return this;  
  92.                 },  
  93.   
  94.                 // Overrides response content-type header  
  95.                 //若是state=0那麼能夠覆蓋這個mimetype!  
  96.                 overrideMimeType: function( type ) {  
  97.                     if ( !state ) {  
  98.                         s.mimeType = type;  
  99.                     }  
  100.                     return this;  
  101.                 },  
  102.   
  103.                 // Status-dependent callbacks  
  104.                 statusCode: function( map ) {  
  105.                     var code;  
  106.                     if ( map ) {  
  107.                         if ( state < 2 ) {  
  108.                             for ( code in map ) {  
  109.                                 // Lazy-add the new callback in a way that preserves old ones  
  110.                                 statusCode[ code ] = [ statusCode[ code ], map[ code ] ];  
  111.                             }  
  112.                         } else {  
  113.                             // Execute the appropriate callbacks  
  114.                             jqXHR.always( map[ jqXHR.status ] );  
  115.                         }  
  116.                     }  
  117.                     return this;  
  118.                 },  
  119.   
  120.                 // Cancel the request  
  121.                 //取消請求  
  122.                 abort: function( statusText ) {  
  123.                     var finalText = statusText || strAbort;  
  124.                     if ( transport ) {  
  125.                         transport.abort( finalText );  
  126.                     }  
  127.                     done( 0, finalText );  
  128.                     return this;  
  129.                 }  
  130.             };  
  131.   
  132.         // Attach deferreds  
  133.         //讓jqXHR具備promise的全部的屬性和方法!不包括狀態改變的方法,如resollveWith等  
  134.         //同時jqXHR的complete對應於completeDeferred的add方法,可是該jqXHR中也封裝了三個Callbacks對象  
  135.         //可是這裏沒有用內部的Callbacks對象,而是採用一個新的Callbacks對象  
  136.         //completeDeferred = jQuery.Callbacks("once memory"),  
  137.         deferred.promise( jqXHR ).complete = completeDeferred.add;  
  138.         //success調用的promise對象內置的done方法對應於的Callbacks對象  
  139.         jqXHR.success = jqXHR.done;  
  140.         //error方法調用的promise對象內置的fail方法對應的Callbacks對象!  
  141.         //注意:這個內置的promise對象的progress方法對應的Callbacks對象沒有用到!  
  142.         jqXHR.error = jqXHR.fail;  
  143.   
  144.         // Remove hash character (#7531: and string promotion)  
  145.         // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)  
  146.         // Handle falsy url in the settings object (#10093: consistency with old signature)  
  147.         // We also use the url parameter if available  
  148.         s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );  
  149.           
  150.         //type就是get或者post。這個方式能夠經過用戶傳入的對象的method或者type或者最終的對象的method或者type獲取!  
  151.         // Alias method option to type as per ticket #12004  
  152.         s.type = options.method || options.type || s.method || s.type;  
  153.   
  154.         // Extract dataTypes list  
  155.         //取出dataType兩邊的空格,同時經過空格進行分組獲得一個數組!dataType="html"  
  156.         s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];  
  157.           
  158.         //若是沒有crossDomain對象  
  159.         // A cross-domain request is in order when we have a protocol:host:port mismatch  
  160.         if ( s.crossDomain == null ) {  
  161.           
  162.             parts = rurl.exec( s.url.toLowerCase() );  
  163.             //若是在同一個域名裏面那麼這裏的判斷都是false,結果就是crossDomain爲false  
  164.             //若是再也不同一個域名裏面,那麼這裏的判斷都是true,結果就是crossDomain爲true!  
  165.             s.crossDomain = !!( parts &&  
  166.                 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||  
  167.                     ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==  
  168.                         ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )  
  169.             );  
  170.         }  
  171.          //若是存在data同時存在processData同時data不是string!  
  172.          //traditional是爲了兼容jQuery<1.3.2行爲的!  
  173.         // Convert data if not already a string  
  174.         if ( s.data && s.processData && typeof s.data !== "string" ) {  
  175.             s.data = jQuery.param( s.data, s.traditional );  
  176.         }  
  177.         // Apply prefilters  
  178.   
  179.         inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );  
  180.        
  181.         //若是在預過濾器中已經終止了請求,那麼直接返回jqXHR對象!  
  182.         // If request was aborted inside a prefilter, stop there  
  183.         if ( state === 2 ) {  
  184.             return jqXHR;  
  185.         }  
  186.   
  187.         // We can fire global events as of now if asked to  
  188.         // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)  
  189.         //若是是global參數,那麼咱們直接trigger事件ajaxStart!  
  190.         fireGlobals = jQuery.event && s.global;  
  191.         // Watch for a new set of requests  
  192.         if ( fireGlobals && jQuery.active++ === 0 ) {  
  193.             jQuery.event.trigger("ajaxStart");  
  194.         }  
  195.   
  196.         // Uppercase the type  
  197.         //把type變成大寫  
  198.         s.type = s.type.toUpperCase();  
  199.       
  200.         // Determine if request has content  
  201.         //rnoContent = /^(?:GET|HEAD)$/  
  202.         //也就是若是沒有指定type也就是請求方式!  
  203.         s.hasContent = !rnoContent.test( s.type );  
  204.   
  205.         // Save the URL in case we're toying with the If-Modified-Since  
  206.         // and/or If-None-Match header later on  
  207.         //獲取url參數!  
  208.         cacheURL = s.url;  
  209.   
  210.         // More options handling for requests with no content  
  211.         //若是指定了請求方式,如get,post等!  
  212.         if ( !s.hasContent ) {  
  213.          //沒有指定請求方式的時候有傳遞數據!  
  214.             // If data is available, append data to url  
  215.             if ( s.data ) {  
  216.                 //var rquery = (/\?/);  
  217.                 //若是url後面有問號,那麼直接把參數綁定到問號後面就能夠了!不然添加問號在綁定!  
  218.                 //同時刪除數據!  
  219.                 cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );  
  220.                 // #9682: remove data so that it's not used in an eventual retry  
  221.                 delete s.data;  
  222.             }  
  223.   
  224.             // Add anti-cache in url if needed  
  225.             //若是指定了cache爲false表示不能進行數據緩存,那麼會在url後面添加一個當前時間!  
  226.             if ( s.cache === false ) {  
  227.               
  228.                   
  229.                 s.url = rts.test( cacheURL ) ?  
  230.   
  231.                     // If there is already a '_' parameter, set its value  
  232.                     //var nonce = jQuery.now();  
  233.                     cacheURL.replace( rts, "$1_=" + nonce++ ) :  
  234.   
  235.                     // Otherwise add one to the end  
  236.                     cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;  
  237.             }  
  238.         }  
  239.   
  240.         // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.  
  241.         //若是添加了ifModified頭  
  242.         //var lastModified={}  
  243.         if ( s.ifModified ) {  
  244.             //若是lastModified保存了這個cacheURL也就是這個URL有緩存了!那麼直接添加頭If-Modified-Since數據爲  
  245.             //jQuery.lastModified[ cacheURL ]獲取到的數據!  
  246.             if ( jQuery.lastModified[ cacheURL ] ) {  
  247.                 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );  
  248.             }  
  249.             //若是在etag: {}中保存了這個URL  
  250.             //那麼添加If-None-Match,由於Etag和if-None-Match是一對,Last-Modified和If-Modified-Since是一對!  
  251.             if ( jQuery.etag[ cacheURL ] ) {  
  252.                 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );  
  253.             }  
  254.         }  
  255.   
  256.         // Set the correct header, if data is being sent  
  257.         //若是有數據傳送,同時也指定了get,post方法,同時contentType也指定!  
  258.         //那麼添加一個頭Content-Type!  
  259.         if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {  
  260.             jqXHR.setRequestHeader( "Content-Type", s.contentType );  
  261.         }  
  262.   
  263.         // Set the Accepts header for the server, depending on the dataType  
  264.         //同時添加請求頭Accept  
  265.         //(1)若是指定了dataType,同時accepts中dataType存在,也就是必須是指定的data[type]  
  266.         jqXHR.setRequestHeader(  
  267.             "Accept",  
  268.             s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?  
  269.             //  allTypes = "*/".concat("*");  
  270.             //若是支持的數據類型是內置的類型,那麼獲取內置的值,如text獲取的就是"text/plain"  
  271.             //同時dataTypes[0]不是"*",那麼咱們加上一個逗號,同時加上後面剩餘的部分!  
  272.             /* 
  273.             var allTypes = "*/".concat("*");  
  274.             //打印  
  275.             //alert(allTypes);  
  276.             //最後的格式就是:text/html,*/*;q=0.01  
  277.             //若是傳入的dataType就是*,那麼最後的結果就是"*/*"  
  278.                 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :  
  279.                 s.accepts[ "*" ]  
  280.         );  
  281.         // Check for headers option  
  282.         //若是還定義了headers選項,那麼會被逐個發送到服務器端!  
  283.         for ( i in s.headers ) {  
  284.             jqXHR.setRequestHeader( i, s.headers[ i ] );  
  285.         }  
  286.   
  287.         // Allow custom headers/mimetypes and early abort  
  288.         //若是指定了beforeSend,同時beforeSend的函數調用的結果是false或者state是2,那麼取消此次請求  
  289.         //beforeSend中傳入的參數爲callbackContext = s.context || s也就是最終對象的context參數爲上下文  
  290.         //第一個參數是XHR對象,第二個參數是最終的options對象!  
  291.         if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {  
  292.             // Abort if not done already and return  
  293.             return jqXHR.abort();  
  294.         }  
  295.         // aborting is no longer a cancellation  
  296.         strAbort = "abort";  
  297.   
  298.         // Install callbacks on deferreds  
  299.         //往jqXHR["success"]和jqXHR["error"],jqXHR["complete"]中添加回調函數  
  300.         //回調函數就是經過最終options對象獲取到的success,error,complete函數!  
  301.         for ( i in { success: 1, error: 1, complete: 1 } ) {  
  302.             jqXHR[ i ]( s[ i ] );  
  303.         }  
  304.   
  305.         // Get transport  
  306.         //傳入的參數是transports對象!這個函數裏面會判斷是否傳入了transports  
  307.         transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );  
  308.         // If no transport, we auto-abort  
  309.         if ( !transport ) {  
  310.             done( -1, "No Transport" );  
  311.         } else {  
  312.             //若是有transport那麼readyState就是1,表示 (載入)已調用send()方法,正在發送請求,也就是請求的發送是在  
  313.             //inspectPrefiltersOrTransports裏面完成的!  
  314.             jqXHR.readyState = 1;  
  315.             // Send global event  
  316.             //指示是否觸發全局Ajax事件。將該值設爲false將阻止全局事件處理函數被觸發  
  317.             //fireGlobals = jQuery.event && s.global;  
  318.             //若是是表示全局ajax事件,那麼咱們要調用ajaxSend方法!同時爲這個方法傳入參數jqXHR和最終option!  
  319.             if ( fireGlobals ) {  
  320.                 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );  
  321.             }  
  322.             // Timeout  
  323.             //若是指定了async同時timeout>0表示指定了隔多少秒就放棄  
  324.             //一個超時調用,超時直接調用abort方法!  
  325.             if ( s.async && s.timeout > 0 ) {  
  326.                 timeoutTimer = setTimeout(function() {  
  327.                     jqXHR.abort("timeout");  
  328.                 }, s.timeout );  
  329.             }  
  330.             //若是有transport,那麼調用send方法!  
  331.             try {  
  332.                 state = 1;  
  333.                 transport.send( requestHeaders, done );  
  334.             } catch ( e ) {  
  335.                 // Propagate exception as error if not done  
  336.                 if ( state < 2 ) {  
  337.                     done( -1, e );  
  338.                 // Simply rethrow otherwise  
  339.                 } else {  
  340.                     throw e;  
  341.                 }  
  342.             }  
  343.         }  


總結:jquery

 

(1)調用 jQuery.ajaxSetup( {}, options )讓最終options具備jQuery內置的全部的屬性,同時也包括用戶調用ajax方法的時候傳入的全部的屬性和方法!

(2)建立jqXHR對象,讓該對象具備Deferred的全部屬性和方法,該Deferred對象能夠綁定用戶的success和error方法。可是用戶傳入的compelte方法表示任何狀況下都會調用,咱們就引入了一個Callbacks對象,把complete回調函數存入該Callback中(用fireWith調用)ajax

(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"事件promise

 

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方法的處理邏輯:

 

[javascript]  view plain  copy
 
  1. function done( status, nativeStatusText, responses, headers ) {  
  2.         var isSuccess, success, error, response, modified,  
  3.             statusText = nativeStatusText;  
  4.         // Called once  
  5.         //若是state是2,那麼直接返回!  
  6.         if ( state === 2 ) {  
  7.             return;  
  8.         }  
  9.         // State is "done" now  
  10.         //state設置爲2表示不會再次執行了!  
  11.         state = 2;  
  12.         // Clear timeout if it exists  
  13.         //若是timeoutTimer存在,那麼直接清除!  
  14.         if ( timeoutTimer ) {  
  15.             clearTimeout( timeoutTimer );  
  16.         }  
  17.         // Dereference transport for early garbage collection  
  18.         // (no matter how long the jqXHR object will be used)  
  19.         transport = undefined;  
  20.         // Cache response headers  
  21.         //獲取response的頭部信息,默認是空!  
  22.         responseHeadersString = headers || "";  
  23.         // Set readyState  
  24.         //若是status>0那麼把readyState設置爲4!  
  25.         jqXHR.readyState = status > 0 ? 4 : 0;  
  26.         // Determine if successful  
  27.         //若是status在指定的區間內那麼表示成功!  
  28.         isSuccess = status >= 200 && status < 300 || status === 304;  
  29.         // Get response data  
  30.         //若是done方法有responses那麼對他進行處理!  
  31.         if ( responses ) {  
  32.             response = ajaxHandleResponses( s, jqXHR, responses );  
  33.         }  
  34.         // Convert no matter what (that way responseXXX fields are always set)  
  35.         response = ajaxConvert( s, response, jqXHR, isSuccess );  
  36.         // If successful, handle type chaining  
  37.         if ( isSuccess ) {  
  38.             // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.  
  39.             //若是ifModified存在,那麼就要設置If-Modified-Since和If-None-Match頭!  
  40.             if ( s.ifModified ) {  
  41.                 modified = jqXHR.getResponseHeader("Last-Modified");  
  42.                 if ( modified ) {  
  43.                     jQuery.lastModified[ cacheURL ] = modified;  
  44.                 }  
  45.   
  46.                 modified = jqXHR.getResponseHeader("etag");  
  47.                 if ( modified ) {  
  48.                     jQuery.etag[ cacheURL ] = modified;  
  49.                 }  
  50.             }  
  51.             // if no content  
  52.             //204表示沒有數據,這時候頁面就不須要跳轉!仍是停留在當前頁面!  
  53.             if ( status === 204 || s.type === "HEAD" ) {  
  54.                 statusText = "nocontent";  
  55.                //若是是304那麼表示沒有修改內容!  
  56.             // if not modified  
  57.             } else if ( status === 304 ) {  
  58.                 statusText = "notmodified";  
  59.                 //若是有數據,那麼咱們獲取到數據!  
  60.             // If we have data, let's convert it  
  61.             } else {  
  62.                 statusText = response.state;  
  63.                 success = response.data;  
  64.                 error = response.error;  
  65.                 isSuccess = !error;  
  66.             }  
  67.         } else {  
  68.         //這裏的else表示請求失敗!咱們從statusText獲取到錯誤的信息,而後對statusText進行處理!  
  69.             // We extract error from statusText  
  70.             // then normalize statusText and status for non-aborts  
  71.             error = statusText;  
  72.             if ( status || !statusText ) {  
  73.                 statusText = "error";  
  74.                 if ( status < 0 ) {  
  75.                     status = 0;  
  76.                 }  
  77.             }  
  78.         }  
  79.         //爲jqXHR設置數據  
  80.         // Set data for the fake xhr object  
  81.         jqXHR.status = status;  
  82.         jqXHR.statusText = ( nativeStatusText || statusText ) + "";  
  83.         // Success/Error  
  84.         if ( isSuccess ) {  
  85.             //若是成功了請求,那麼咱們傳入的Context是callbackContext,傳入的數據是response.data  
  86.             //response.status和jqXHR對象  
  87.             deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );  
  88.         } else {  
  89.             deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );  
  90.         }  
  91.         // Status-dependent callbacks  
  92.         jqXHR.statusCode( statusCode );  
  93.         statusCode = undefined;  
  94.            //若是是全局執行  
  95.         if ( fireGlobals ) {  
  96.             globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",  
  97.                 [ jqXHR, s, isSuccess ? success : error ] );  
  98.         }  
  99.         // Complete  
  100.         //這個對象添加的全部函數執行,表示完成,不是成功,失敗,而是complelte表示無論成功與否都是會執行的!  
  101.         //並且只會執行一次!  
  102.         completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );  
  103.         if ( fireGlobals ) {  
  104.             //globalEventContext也就是最終options的事件,觸發事件ajaxComplete!  
  105.             globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );  
  106.             // Handle the global AJAX counter  
  107.             //若是全局的ajax計數器已是0了,那麼就會觸發ajaxStrop事件!  
  108.             if ( !( --jQuery.active ) ) {  
  109.                 jQuery.event.trigger("ajaxStop");  
  110.             }  
  111.         }  
  112.     }  
  113.   
  114.     return jqXHR;  
  115. }  
  116. );  

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!

相關文章
相關標籤/搜索