標籤:des style blog http color get
綜合前面的分析,我們總結如下3大塊:
- jQuery1.5以後,AJAX模組提供了三個新的方法用於管理、擴充AJAX請求
- 前置過濾器 jQuery. ajaxPrefilter
- 請求分發器 jQuery. ajaxTransport
- 類型轉換器 ajaxConvert
- 為了整體性與擴充性考慮,把整個結構通過Deferred實現非同步鏈式模型,Promise對象可以輕易的綁定成功、失敗、進行中三種狀態的回呼函數,然後通過在狀態代碼在來回調不同的函數就行了
- 出於同源策略考慮,存在跨域問題,所以ajax內部的處理總的來分2大塊
- 基於XMLHttpRequest的ajax請求
- 基於script的jsonp跨域請求
引入Deferred統一回調體系
jQuery的鏈式方法是大是通過返回this的引用,但是ajax的鏈式不是那麼簡單的,因為ajax可以非同步作業,所以返回的是一個非同步模型對象Promise
當然如果只是deferred = jQuery.Deferred() 返回這個對象也是沒意義的,因為無法關聯到實際的資料
所以jquery內部構建了一個增強版的jqXHR對象,除了混入Promise模型,還增強了一些方法與介面
jqXHR 擴充基本的方法與介面
jqXHR = { // 準備狀態 readyState: 0, // Builds headers hashtable if needed // 如果需要,建立一個回應標頭參數的表 getResponseHeader: function(key) { var match; // 如果狀態為2,狀態2表示ajax完成 if (state === 2) { // 如果沒有相應頭 if (!responseHeaders) { // 相應頭設空 responseHeaders = {}; // 組裝相應頭 while ((match = rheaders.exec(responseHeadersString))) { responseHeaders[match[1].toLowerCase()] = match[2]; } } // 回應標頭對應的key的值 match = responseHeaders[key.toLowerCase()]; } return match == null ? null : match; }, // Raw string // 返迴響應頭字串 getAllResponseHeaders: function() { // 看看是否接收到了,接收到直接返回,否則為null return state === 2 ? responseHeadersString : null; }, // Caches the header // 佈建要求頭 setRequestHeader: function(name, value) { var lname = name.toLowerCase(); if (!state) { // 如果requestHeadersNames[ lname ]不為空白, // 則requestHeadersNames[ lname ]不變,name設定為該值 // 否則,requestHeadersNames[ lname ]不空, // 則requestHeadersNames[ lname ]設定為name, // 該映射關係用於避免使用者大小寫書寫錯誤之類的問題,容錯處理 name = requestHeadersNames[lname] = requestHeadersNames[lname] || name; //現在的name是對的,或者是第一次設定這個name,不需要容錯 //佈建要求頭對應值 requestHeaders[name] = value; } return this; }, // Overrides response content-type header // 重寫相應頭content-type overrideMimeType: function(type) { if (!state) { s.mimeType = type; } return this; }, // Status-dependent callbacks // 對應狀態的回呼函數集 statusCode: function(map) { var code; if (map) { //如果狀態小於2,表示舊的回調可能還沒有用到 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 // 無論Deferred成功還是失敗都執行目前狀態回調 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; }};
看看我們ajax的寫法
$.ajax({ url: "php.html", context: document.body, complete: function() { console.log(this) }}).done(function() { console.log(this)});
鏈式了一個done方法,done是Promise模型中的成功回調,因為ajax返回的是jqXHR對象
所以jqXHR就需要混入Promise模型
deferred.promise(jqXHR).complete = completeDeferred.add; jqXHR.success = jqXHR.done; jqXHR.error = jqXHR.fail;
看ajax源碼前需要瞭解回到隊列與Deferreds
jqXHR混入了Promise模型處理,當然只能讀防止修改,之外還增加了一個complete的的回調隊列
具體怎麼使用,看後面
for (i in { success : 1, error : 1, complete : 1}) { jqXHR[i](s[i]);}
很巧妙的一個處理,把使用者設定檔中的回呼函數給註冊到這個jqXHR的回調體系中
所以就把所有的有關回調都綁定到了jqXHR對象上了
ajax提供3種事件通知介面
1 提供全域事件,外部的視圖可以根據ajax狀態進行改變
2 提供內部事件介面,根據流程做相對應的處理
3 提供鏈式事件介面,通過Promise實現
當ajax開始時類比全域事件,ajaxStart
這裡主要利用了jQuery.event.trigger和jQuery.fn.trigger類比發事件
if (fireGlobals && jQuery.active++ === 0) { // 則通過jQuery.event.trigger類比觸發 jQuery.event.trigger("ajaxStart");}
ajax發送訊息,觸發ajaxSend
/** * 全域事件ajaxSend * 如果需要,對特定對象觸發全域事件ajaxSend */if (fireGlobals) { globalEventContext.trigger("ajaxSend", [jqXHR, s]);}
結束時觸發ajaxSuccess或ajaxError,再出發ajaxComplete,如果全部ajax結束則觸發ajaxStop。
if (fireGlobals) { globalEventContext.trigger(isSuccess ? "ajaxSuccess" : "ajaxError", [jqXHR, s, isSuccess ? success : error]); } // Complete completeDeferred.fireWith(callbackContext, [jqXHR, statusText]); if (fireGlobals) { globalEventContext.trigger("ajaxComplete", [jqXHR, s]); // Handle the global AJAX counter if (!(--jQuery.active)) { jQuery.event.trigger("ajaxStop"); } }
關於快取資料
如果我們的請求為GET的時候的處理,使用者通過data自訂了一些資料,那麼這些資料只能通過拼接成url傳遞給服務端
我們需要通過給地址附加參數_=xxx來避免緩衝
if (s.cache === false) { s.url = rts.test(cacheURL) ? // If there is already a ‘_‘ parameter, set its value cacheURL.replace(rts, "$1_=" + ajax_nonce++) : // Otherwise add one to the end cacheURL + (ajax_rquery.test(cacheURL) ? "&" : "?") + "_=" + ajax_nonce++;}
從jQuery 1.5開始,$.ajax()
返回XMLHttpRequest(jqXHR)對象,該對象是瀏覽器的原生的XMLHttpRequest對象的一個超集。
例如,它包含responseText
和responseXML
屬性,以及一個getResponseHeader()
方法。
當傳輸機制不是是XMLHttpRequest時(例如,一個JSONP請求指令碼,返回一個指令碼 tag 時),jqXHR對象儘可能的類比原生的XHR功能。
從jQuery 1.5.1開始, jqXHR
對象還包含了overrideMimeType
方法 (它在jQuery 1.4.x中是有效,但是在jQuery 1.5中暫時的被移除)。
.overrideMimeType()
方法可能用在beforeSend()
的回呼函數中,
例如,修改響應的Content-Type資訊頭:
$.ajax({ url: "http://fiddle.jshell.net/favicon.png", beforeSend: function ( xhr ) { xhr.overrideMimeType("text/plain; charset=x-user-defined"); }}).done(function ( data ) { if( console && console.log ) { console.log("Sample of data:", data.slice(0, 100)); }});
從 jQuery 1.5 開始,$.ajax()
返回的jqXHR對象 實現了 Promise 介面, 使它擁有了 Promise 的所有屬性,方法和行為。(見Deferred object擷取更多資訊)。
為了讓回呼函數的名字統一,便於在$.ajax()
中使用。jqXHR也提供.error()
.success()
和.complete()
方法。這些方法都帶有一個參數,該參數是一個函數,此函數在 $.ajax()
請求結束時被調用,並且這個函數接收的參數,與調用 $.ajax()
函數時的參數是一致。這將允許你在一次請求時,對多個回呼函數進行賦值,甚至允許你在請求已經完成後,對回呼函數進行賦值(如果該請求已經完成,則回呼函數會被立刻調用)。
更多的更多大家還是仔細參考API吧