標籤:
ajax在得到請求響應後主要會做兩個處理:擷取響應資料和使用類型轉化器轉化資料
a.擷取響應資料
擷取響應資料是調用ajaxHandleResponses函數來處理。
ajaxHandleResponses的功能有:
- 為jqXHR設定所有responseXXX欄位(值便是響應資料)
- 找到正確的dataType (在content-type和預期的dataType兩者中的一個)
- 返回正確的響應資料
我們看一個響應資料的格式:
responses = { text: "{"code":500,"data":null,"message":"all exist","sessionId":"wsdfhl333sdfs"}"
}
設定responseXXX只有兩種responseXML和responseText
//填寫responseXXX(responseXML/responseText)欄位, for ( type in responseFields ) { if ( type in responses ) { jqXHR[ responseFields[type] ] = responses[ type ]; } }
找到正確的dataType。這是一個逐一探測的過程
// 除去自動添加的dataType類型,同時在此過程中獲得Content-Type類型 while( dataTypes[ 0 ] === "*" ) { dataTypes.shift(); if ( ct === undefined ) { ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); } } //檢查我們是否正在處理一個已知的content-type if ( ct ) { for ( type in contents ) { if ( contents[ type ] && contents[ type ].test( ct ) ) { dataTypes.unshift( type ); break; } } } //檢查看看我們是否有預期的資料類型的響應 if ( dataTypes[ 0 ] in responses ) { finalDataType = dataTypes[ 0 ]; } else { //嘗試可轉換的資料類型 for ( type in responses ) { if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { finalDataType = type; break; } if ( !firstDataType ) { firstDataType = type; } } // Or just use first one finalDataType = finalDataType || firstDataType; }
返回正確的響應資料
// 如果我們找到一個dataType // 把dataType到dataTypes中去,如果需要的話 // 返回相應的響應資料 if ( finalDataType ) { if ( finalDataType !== dataTypes[ 0 ] ) { dataTypes.unshift( finalDataType ); } return responses[ finalDataType ]; }}
b.類型轉化器
ajax有四種轉換器
converters: { // 任意內容轉換為字串 // window.String 將會在min檔案中被壓縮為 a.String "* text": window.String, // 文本轉換為HTML(true表示不需要轉換,直接返回) "text html": true, // 文本轉換為JSON對象 "text json": jQuery.parseJSON, // 文本轉換為XML "text xml": jQuery.parseXML }
其中jQuery.parseJSON/jQuery.parseXML點擊看詳情
除此之外還有為script專門拓展的
// Ajax請求設定預設的值jQuery.ajaxSetup({ /** * 內容類型發送要求標頭(Content-Type),用於通知伺服器該請求需要接收何種類型的返回結果。 * 如果accepts設定需要修改,推薦在$.ajaxSetup() 方法中設定一次。 * @type {Object} */ 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; }}
還有一個在jsonp預先處理的時候添加的
s.converters["script json"] = function() { if ( !responseContainer ) { jQuery.error( callbackName + " was not called" ); } return responseContainer[ 0 ]; };
dataType無非就那麼幾種情況
1:dataType為空白,自動轉化
此時jQuery只能根據報文頭資訊是猜測當前需要處理的類型(ajaxHandleResponses中)
// 刪除掉通配dataType,得到返回的Content-Typewhile (dataTypes[0] === "*") { dataTypes.shift(); if (ct === undefined) { ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); }}
通過xhr.getAllResponseHeaders()得到報文頭資訊,然後去匹配Content-Type所有對象的值即可
當然找到這個Content-Type = “html”,我們還得看看有沒有對應處理的方法,如果有就需要替換這個dataTypes(ajaxHandleResponses中)
// 看看是不是我們能處理的Content-Type,比片這類二進位類型就不好處理了if (ct) { // 實際上能處理的就是text、xml和json for (type in contents) { if (contents[type] && contents[type].test(ct)) { dataTypes.unshift(type); break; } }}
經過這個流程後,dataTypes 本來是* 就變成了對應的html了,這是jquery內部的自動轉化過程。
2:dataType開發人員指定
xml, json, script, html, jsop
最終ajax成功以後統一調用ajaxConvert函數處理。所以轉換器總結起來就一句話:類型轉換器將服務端響應的responseText或responseXML,轉換為請求時指定的資料類型dataType,如果沒有指定類型就依據回應標頭Content-Type自動處理。根據目標類型選擇響應的轉換器轉換成目標資料。
c.
jQuery. ajaxSetup ( target[, settings] )
函數如果用於外部使用沒有settings這個參數:用於設定AJAX的全域預設設定。
這個函數有兩個用法
1.當target、settings兩個參數傳遞的時候,建立一個完整成熟的設定對象(包含ajaxSettings和傳遞的settings)寫入到target中。最終jQuery.ajaxSettings這個全域變數沒有改變。這個用法主要是jQuery內部使用,外部使用沒有意義。
2.當settings不存在的時候(即只有一個參數),則將target寫入jQuery.ajaxSettings。這個用法在外部使用較多。主要是設定AJAX的全域預設設定。
查看源碼
//建立一個完整成熟的設定對象(包含ajaxSettings和傳遞的settings)寫入到target中。//如果settings省略,則將target寫入ajaxSettings.ajaxSetup: function( target, settings ) { return settings ? ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : ajaxExtend( jQuery.ajaxSettings, target );}
使用到ajaxExtend函數,通過jQuery.ajaxSettings.flatOptions指定那些選項不做深度拓展(深度拷貝替換),其他的都做深度拓展。預設的不做深度拓展的選項只有兩個jQuery.ajaxSettings.flatOptions: {url: true,context: true}。外部可以直接將不做深度拓展的選項添加到jQuery.ajaxSettings.flatOptions上。
//為ajax選項專門做拓展的函數//對flatOptions裡面的選項(不需要深度拓展(深度拷貝替換))function ajaxExtend( target, src ) { var deep, key, flatOptions = jQuery.ajaxSettings.flatOptions || {}; //針對不需要深度拓展的選項儲存在target[key]中,需要深度拓展的選項儲存在deep[key]中。 for ( key in src ) { if ( src[ key ] !== undefined ) { ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ]; } } //將deep中的內容深度拓展(深度拷貝替換)到target中 if ( deep ) { jQuery.extend( true, target, deep ); } return target;}
d. ajax相關api
jQuery.get(url [, data ] [, success ] [, type ])(函數用於通過HTTP GET形式的AJAX請求擷取遠端資料。
jQuery.get()函數用於實現簡單的GET形式的AJAX請求,它在底層是使用jQuery.ajax()來實現的,只是省略了大多數不常用的參數設定,並僅限於HTTP GET方式。請注意,該函數是通過非同步方式載入資料的。這裡介紹的jQuery.get()是一個全域方法(無需建立jQuery對象即可調用,你可以理解為靜態函數)。jQuery中還有一個同名的執行個體方法get(),用於擷取當前jQuery對象中匹配的指定索引的DOM元素。)
jQuery.post(url [, data ] [, success ] [, type ])(函數用於通過HTTP POST形式的AJAX請求擷取遠端資料。
jQuery.post()函數用於實現簡單的POST形式的Ajax請求,它在底層是使用jQuery.ajax()來實現的,只是省略了大多數不常用的參數設定,並僅限於HTTP POST方式。請注意,該函數是通過非同步方式載入資料的)
jQuery.getJSON(url [, data ] [, success ])(函數用於通過HTTP GET形式的AJAX請求擷取遠程JSON編碼的資料。JSON是一種資料格式,JS原生支援JSON格式,通過jQuery.getJSON()從伺服器獲得的JSON資料,jQuery會先嘗試將其轉為對應的JS對象。如果請求的URL中包括"callback=?"等類似的部分,jQuery會自動將其視作JSONP,並執行對應的回呼函數來擷取JSON資料。
重要注意:伺服器返回的JSON資料必須符合嚴格的JSON文法,例如:所有屬性名稱必須加雙引號,所有字串值也必須加雙引號(而不是單引號)。請注意,該函數是通過非同步方式載入資料的。)
jQuery.getScript(url [, success ])(函數用於通過HTTP GET形式的載入JavaScript檔案並運行它。該函數用於動態載入JS檔案,並在全域範圍下執行檔案中的JS代碼。該函數可以載入跨域的JS檔案。請注意,該函數是通過非同步方式載入資料的)
jQuery.fn.load(url [, data ] [, complete ])(函數用於從伺服器載入資料,並使用返回的html內容替換當前匹配元素的內容。load()函數預設使用GET方式,如果提供了對象形式的資料,則自動轉為POST方式。load()函數只會替換每個匹配元素的內部內容(innerHTML),所以他會預設dataType為html。你還可以在URL字串後面追加指定的選取器(與URL之間用空格隔開),以便於只使用載入的html文檔中匹配選取器的部分內容來替換當前匹配元素的內容。如果該文檔沒有匹配選取器的內容,就使用Null 字元串("")來替換當前匹配元素的內容。
如果當前jQuery對象沒有匹配任何元素,則不會執行遠程載入請求。
這裡介紹的load()是一個Ajax請求函數,jQuery中還有一個同名的事件函數load(),用於在文檔載入完成時執行指定的函數。該函數屬於jQuery對象(執行個體)。該函數在底層是基於函數jQuery.ajax()實現的)
jQuery.ajaxPrefilter([ dataType ,] handler)(函數用於指定預先處理Ajax參數選項的回呼函數。在所有參數選項被jQuery.ajax()函數處理之前,你可以使用該函數設定的回呼函數來預先更改任何參數選項。
你還可以指定資料類型(dataType),從而只預先處理指定資料類型的參數選項。該函數可以調用多次,以便於為不同資料類型的AJAX請求指定不同的回呼函數
dataType(可選/String類型)
一個或多個用空格隔開的資料類型所組成的字串。如果未指定該參數,則表示所有資料類型。可用的資料類型為"xml"、 "html"、 "text"、 "json"、 "jsonp"、 "script"。該字串為它們之間的任意組合(多種類型用空格隔開),例如:"xml"、 "text html"、 "script json jsonp"。
handler (Function類型)
用於預先處理參數選項的回呼函數。它有以下3個參數:
options:(Object對象)當前AJAX請求的所有參數選項。
originalOptions:(Object對象)傳遞給$.ajax()方法的未經修改的參數選項。
jqXHR:當前請求的jqXHR對象(經過jQuery封裝的XMLHttpRequest對象)。
)
jQuery.ajaxSetup(settingsObj) (函數用於設定AJAX的全域預設設定。該函數用於更改jQuery中AJAX請求的預設設定選項。之後執行的所有AJAX請求,如果對應的選項參數沒有設定,將使用更改後的預設設定。)
jQuery.fn.serialize()(函數用於序列化一組表單元素,將表單內容編碼為用於提交的字串。serialize()函數常用於將表單內容序列化,以便用於AJAX提交。
該函數主要根據用於提交的有效表單控制項的name和value,將它們拼接為一個可直接用於表單提交的文本字串,該字串已經過標準的URL編碼處理(字元集編碼為UTF-8)。
該函數不會序列化不需要提交的表單控制項,這和常規的表單提交行為是一致的。例如:不在<form>標籤內的表單控制項不會被提交、沒有name屬性的表單控制項不會被提交、帶有disabled屬性的表單控制項不會被提交、沒有被選中的表單控制項不會被提交。
與常規表單提交不一樣的是:常規表單一般會提交帶有name的按鈕控制項,而serialize()函數不會序列化帶有name的按鈕控制項。)
jQuery.fn.serializeArray()(函數用於序列化一組表單元素,將表單內容編碼為一個JavaScript數組。常用於將表單內容序列化為JSON對象,以便於被編碼為JSON格式的字串。
該函數會將可用於提交的每個表單控制項封裝成一個Object對象,該對象有name和value屬性,對應該表單控制項的name和value屬性。然後將這些Object對象封裝為一個數組並返回。
該函數不會序列化不需要提交的表單控制項,這和常規的表單提交行為是一致的。例如:不在<form>標籤內的表單控制項不會被提交、沒有name屬性的表單控制項不會被提交、帶有disabled屬性的表單控制項不會被提交、沒有被選中的表單控制項不會被提交。
與常規表單提交不一樣的是:常規表單一般會提交帶有name的按鈕控制項,而serializeArray()函數不會序列化帶有name的按鈕控制項。)
jQuery.param(obj [, traditional ])(將一個JS數組或純粹的對象序列化為字串值,以便用於URL查詢字串或AJAX請求。如果傳入的不是數組或"純粹的對象",則返回Null 字元串("");如果傳入的是null、undefined等無法訪問屬性的值,則直接報錯。
所謂"純粹的對象",就是通過{}或new Object()自行建立的對象。JS內建的Boolean、Number、String、Date、RegExp、Function、Window等類型的對象都不算是"純粹的對象"。
返回的字串已經過URL編碼處理(採用的字元集為UTF-8))
jQuery.fn.ajaxStart(handlerFn)(為AJAX請求的ajaxStart事件綁定處理函數)
jQuery.fn.ajaxSend(handlerFn)(設定當AJAX請求即將被發送時執行的回呼函數。)
jQuery.fn.ajaxComplete(handlerFn)(設定當AJAX請求完成(無論成功或失敗)時執行的回呼函數。)
jQuery.fn.ajaxSuccess(handlerFn)(設定當AJAX請求成功完成時執行的回呼函數。)
jQuery.fn.ajaxError(handlerFn)(設定當AJAX請求失敗時執行的回呼函數。)
jQuery.fn.ajaxStop(handlerFn)(為AJAX請求的ajaxStop事件綁定處理函數。)
到此為止,jQuery 1.9.1版本的源碼分析完畢。歡迎拍磚指正。
如果覺得本文不錯,請點擊右下方【推薦】!
jQuery-1.9.1源碼分析系列(十六)ajax——響應資料處理和api整理