AJAX 全稱 Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)。它並非一種新的技術,而是以下幾種原有技術的結合體。
1) 使用CSS和XHTML來表示。
2) 使用DOM模型來交互和動態顯示。
3) 使用XMLHttpRequest來和服務器進行異步通信。
4) 使用javascript來綁定和調用。
通過AJAX異步技術,可以在客戶端腳本與web服務器交互數據的過程中使用XMLHttpRequest對象來完成HTTP請求(Request)/應答(Response)模型:
1) 不需要用戶等待服務端響應。在異步派發XMLHttpRequest請求后控制權馬上就被返回到瀏覽器。界面不會出現白板,在得到服務器響應之前還可以友好的給出一個加載提示。
2) 不需要重新加載整個頁面。為XMLHttpRequest注冊一個回調函數,待服務器響應到達時,觸發回調函數,並且傳遞所需的少量數據。“按需取數據”也降低了服務器的壓力。
3) 不需要使用隱藏或內嵌的框架。在XHR對象之前,模擬Ajax通信通常使用hack手段,如使用隱藏的或內嵌的框架(<iframe>標簽)。
下面介紹下AJAX中的重要對象:XMLHttpRequest。
XMLHttpRequest對象(XHR)
XMLHttpRequest是一套可以在Javascript、VbScript、Jscript等腳本語言中通過http協議傳送或接收XML及其他數據的一套API。
XMLHttpRequest對象首次以ActiveX對象形式在微軟Internet Explorer(IE) 5中以引入。其他瀏覽器制造商在認識到這一對象重要性后也紛紛實現了XMLHttpRequest對象,但是以一個本地JavaScript對象而不是作為一個ActiveX對象實現。而如今,由於安全性、標准等問題,微軟已經在其IE 7中把XMLHttpRequest實現為一個本地JavaScript對象。
API |
描述 |
||||||||||||||
客服端請求 |
|||||||||||||||
open(method,url,async, bstrUser, bstrPassword) |
規定請求的類型、URL 以及是否異步處理請求。 1) method:請求的類型,例如:POST、GET、PUT及PROPFIND。大小寫不敏感。 2) url:請求的URL地址,可以為絕對地址也可以為相對地址。 3) async[可選]:true(默認,異步)或 false(同步)。 注釋:當您使用async=false 時,JavaScript 會等到服務器響應就緒才繼續執行。如果服務器繁忙或緩慢,應用程序會掛起或停止。此時,不需要編寫onreadystatechange回調函數,把代碼放到 send() 語句后面即可。 4) bstrUser[可選]:如果服務器需要驗證,此處指定用戶名,如果未指定,當服務器需要驗證時,會彈出驗證窗口。 5) bstrPassword[可選]:驗證信息中的密碼部分,如果用戶名為空,則此值將被忽略。 |
||||||||||||||
getRequestHeader(name) |
獲取指定的相應頭部信息 |
||||||||||||||
setRequestHeader(name,value) |
自定義HTTP頭部信息。需在open()方法之后和send()之前調用,才能成功發送請求頭部信息。 傳送門:HTTP 頭部詳解
默認情況下,服務器對POST請求和提交Web表單不會一視同仁,將Content-Type頭部信息設置為application/x-www-form-urlencoded (模擬表單提交) |
||||||||||||||
send(string) |
將請求發送到服務器。參數string僅用於POST請求;對於GET請求的參數寫在url后面,所以string參數傳遞null。 |
||||||||||||||
abort() |
調用此方法可取消異步請求,調用后,XHR對象停止觸發事件,不允許訪問任何與響應相關的屬性; |
||||||||||||||
服務端響應 |
|||||||||||||||
onreadystatechange事件 |
對於異步請求,如果需要對服務器獲取和操作響應結果,則在send() 之前,需要為onreadystatechange屬性指定處理方法。該函數用於對服務器響應進行處理。 |
||||||||||||||
readyState |
存有XMLHttpRequest的狀態。每當readyState改變時,就會觸發onreadystatechange事件。 從 0 到 4 發生變化:
|
||||||||||||||
status(數字表示) |
返回當前請求的http狀態碼。 傳送門:HTTP狀態碼一覽表(HTTP Status Code)
|
||||||||||||||
statusText(字符表示) |
返回當前請求的狀態文本eg:OK (status:200) |
||||||||||||||
responseText |
將響應信息作為字符串返回 |
||||||||||||||
responseXML |
將響應信息格式化為Xml Document對象並返回 |
||||||||||||||
responseBody(只有微軟的IE支持) |
將響應信息正文以unsigned byte數組形式返回(二進制數據) |
||||||||||||||
responseStream(只有IE的某些版本支持) |
以Ado Stream對象(二進制流)的形式返回響應信息 |
||||||||||||||
getResponseHeader(name) |
從響應信息中獲取指定的http頭 |
||||||||||||||
getAllResponseHeaders() |
獲取響應的所有http頭 |
||||||||||||||
overrideMimeType |
通常用於重寫服務器響應的MIME類型。Eg,正常情況下XMLHttpRequest只接收文本數據,但我們可以重寫MIME為“text/plain; charset=x-user-defined”,以欺騙瀏覽器避免瀏覽器格式化服務器返回的數據,以實現接收二進制數據。 |
一個簡單的ajax封裝:
var myAjax = { // XMLHttpRequest IE7+, Firefox, Chrome, Opera, Safari ; ActiveXObject IE6, IE5 xhr: window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'), get: function (url, callback) { this.xhr.open('get', url); this.onreadystatechange(callback, this.xhr); this.xhr.send(null); }, post: function (url, data, callback) { this.xhr.open('post', url); this.xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); this.onreadystatechange(callback, this.xhr); this.xhr.send(data); }, onreadystatechange: function (func, _xhr) { _xhr.onreadystatechange = function () { if (_xhr.readyState == 4) { if (_xhr.status == 200) { func(_xhr.responseText); } } } } }
使用:
$('#btn_nowTime1').bind('click', null , function () { myAjax.post('AjaxHandler.ashx', 'func=GetServerTime' , function (data) { if (data) alert(data); } ); });
XMLHttpRequest Level 2
XMLHttpRequest是一個瀏覽器接口,使得Javascript可以進行 HTTP (S) 通信。但是,這個接口一直沒有標准化,每家瀏覽器的實現或多或少有點不同。HTML 5 的概念形成后,W3C 開始考慮標准化這個接口。2008年 2 月,提出了XMLHttpRequest Level 2 草案。
1. 老版本的缺點
老版本的XMLHttpRequest對象有以下幾個缺點:
1) 只支持文本數據的傳送,無法用來讀取和上傳二進制文件。
2) 傳送和接收數據時,沒有進度信息,只能提示有沒有完成。
3) 受到"同域限制"(Same Origin Policy),只能向同一域名的服務器請求數據。
2. 新版本的功能
新版本的XMLHttpRequest對象,針對老版本的缺點,做出了大幅改進。
1) 可以設置 HTTP 請求的時限。
2) 可以使用FormData對象管理表單數據。
3) 可以上傳文件。
4) 可以請求不同域名下的數據(跨域資源共享,Cross-origin resource sharing,簡稱 CORS)。
5) 可以獲取服務器端的二進制數據。
6) 可以獲得數據傳輸的進度信息。
3. 介紹幾個XMLHttpRequest Leve2 新增的成員
超時時限 |
|
timeout |
設置ajax請求超時時限,過了這個時限,就自動停止 HTTP 請求。 |
ontimeout事件 |
當ajax超過timeout 時限時觸發的回調函數。 |
指定響應格式 |
|
responseType |
(默認:“text”)在發送請求前,根據您的數據需要,將xhr.responseType設置為“text”、“arraybuffer”、“blob”或“document”。 |
response |
成功發送請求后,xhr的響應屬性會包含DOMString、ArrayBuffer、Blob 或 Document 形式(具體取決於responseTyp的設置)的請求數據。 |
進度信息 |
|
progress 事件 |
在XMLHttpRequest對象傳遞數據的時候用來返回進度信息。它分成上傳和下載兩種情況。下載的 progress 事件屬於XMLHttpRequest對象,上傳的 progress 事件屬於XMLHttpRequest.upload對象。即: xhr.onprogress = updateProgress; xhr.upload.onprogress = updateProgress; XHR還新增了與progress事件相關的五個事件: 1) load 事件:傳輸成功完成。 2) abort 事件:傳輸被用戶取消。 3) error 事件:傳輸中出現錯誤。 4) loadstart事件:傳輸開始。 5) loadEnd事件:傳輸結束,但是不知道成功還是失敗。 |
4. 一個新功能實例
1) 接收二進制數據(方法A:改寫MIMEType)
老版本的XMLHttpRequest對象,只能從服務器取回文本數據。但我們可以改寫數據的MIMEType,將服務器返回的二進制數據偽裝成文本數據,並且告訴瀏覽器這是用戶自定義的字符集。
關鍵代碼如下:
服務端
String str = "二進制數據獲取"; MemoryStream _memory = new MemoryStream(); BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(_memory, str); _memory.Position = 0; byte[] read = new byte[_memory.Length]; _memory.Read(read, 0, read.Length); _memory.Close(); context.Response.ContentType = "text/plain"; // 服務器使用OutputStream輸出二進制流 context.Response.OutputStream.Write(read, 0, read.Length);
客服端
$('#btn_mime').bind('click', null , function () { $.ajax('AjaxHandler.ashx?func=GetBinaryData', { type: 'get', dataType: 'text', cache: false, mimeType: 'text/plain; charset=x-user-defined', success: function (data) { if (data) { var byte = []; for (var i = 0, len = data.length; i < len; ++i) { var c = data.charCodeAt(i); byte[byte.length] = c & 0xff; } alert(byte); } } }); });
瀏覽器會把相應數據當做文本數據接收,所以我們還必須再一個個字節地還原成二進制數據。位運算"c & 0xff",表示在每個字符的兩個字節之中,只保留后一個字節,將前一個字節扔掉。原因是瀏覽器解讀字符的時候,會把字符自動解讀成Unicode 的 0xF700-0xF7ff 區段。
截圖如下:(測試環境:google Chrome 版本 26.0.1410.43)
服務器端返回二進制數據:
客服端輸出:
a) 使用mimeType: 'text/plain; charset=x-user-defined'參數。
b) 沒有對服務器的MIME類型進行重寫,導致返回信息被瀏覽器格式化后輸出的二進制數據與服務器不同。並且不同瀏覽器格式化后輸出的二進制數據都有差異。
2) 接收二進制數據(方法B:responseType屬性)
在XMLHttpRequest Level2中,可以使用新增的responseType屬性從服務器取回二進制數據。把responseType設為 blob,表示服務器傳回的是二進制對象。
var xhr = new XMLHttpRequest(); xhr.open ('GET', '/path/to/image.png'); xhr.responseType = 'blob';
接收數據的時候,用瀏覽器自帶的 Blob 對象即可。注意,讀取的xhr.response,而不是xhr.responseText。
var blob = new Blob ([xhr.response], {type: 'image/png'});
還可以將responseType設為arraybuffer,把二進制數據裝在一個數組里。然后再遍歷這個數組。
var xhr = new XMLHttpRequest (); xhr.open ('GET', '/path/to/image.png'); xhr.responseType = "arraybuffer"; var arrayBuffer = xhr.response; if (arrayBuffer) { var byteArray = new Uint8Array (arrayBuffer); for (vari = 0; i<byteArray.byteLength; i++) { // do something } }
5. 更多XMLHttpRequest Level 2新功能描述請看:
2) XMLHttpRequest Level 2 使用指南
jQuery框架的Ajax
jQuery是一個快速、簡單的JavaScript library,核心理念是write less,do more(寫的更少,做的更多)。它簡化了HTML 文件的traversing,事件處理、動畫、Ajax 互動,從而方便了網頁制作的快速發展。jQuery是為改變你編寫JavaScript 的方式而設計的。更多jQuery科普知識請看:jQuery百度百科(Eg:模塊,歷史版本)
下面介紹下jQuery框架中ajax相關API:
版本Jquery-1.7.1.js。
1. jQuery.ajax( [url,] options )
通過 HTTP 請求加載遠程數據。
返回值:$.ajax() 返回jqXHR對象(jqXHR對象:為XMLHttpRequest對象的超集)。可用於手動終止請求abort()、為ajax函數設置額外的回調函數等。
ajax內部實現的兩個重要對象:s對象和jqXHR對象。
1) s對象
由默認設置jQuery.ajaxSettings對象、options參數集合和jQuery.ajaxSetup({})默認設置合並而成s對象。
參數名 |
描述 |
|||||||||||||
可由ajax的options參數設置 |
||||||||||||||
url |
(默認: 當前頁地址) 要請求的目的URL地址。 |
|||||||||||||
username password |
用於響應HTTP訪問認證請求的用戶名及密碼 |
|||||||||||||
type |
(默認: "GET") 請求方式 ("POST" 或 "GET")。注意:其它 HTTP 請求方法,如 PUT 和 DELETE 也可以使用,但僅部分瀏覽器支持。 |
|||||||||||||
預期服務器返回的數據類型。如果不指定,jQuery將自動根據 HTTP 包 MIME 信息來智能判斷,比如 XML MIME 類型就被識別為 XML。隨后服務器端返回的數據會根據這個值解析后,傳遞給回調函數。 必須確保網頁服務器報告的 MIME 類型與我們選擇的dataType所匹配。比如說,XML的話,服務器端就必須聲明 text/xml 或者 application/xml 來獲得一致的結果。 可用值:
其中,text 和 xml 類型返回的數據不會經過處理。數據僅僅簡單的將XMLHttpRequest的responseText或responseHTML屬性傳遞給 success 回調函數。 如果指定了 script 或者jsonp類型,那么當從服務器接收到數據時,實際上是用了<script>標簽而不是XMLHttpRequest對象。這種情況下,$.ajax() 不再返回一個XMLHttpRequest對象,並且也不會傳遞事件處理函數,比如beforeSend。 |
||||||||||||||
contentType |
(默認: "application/x-www-form-urlencoded")標明發送或者接收的實體的MIME類型。當“非GET或HEAD請求”的HTTP請求時,會被設置為HTTP頭請求信息。 |
|||||||||||||
mimeType |
多用途互聯網郵件擴展(MIME,Multipurpose Internet Mail Extensions);用於重寫服務器端響應的MIME類型。 |
|||||||||||||
data |
發送到服務器的數據。可以是一個查詢字符串,比如 key1=value1&key2=value2 ,也可以是一個映射,比如 {key1: 'value1', key2: 'value2'} 。如果使用了后者的形式,則數據在發送前會通過jQuery.param()函數轉換成查詢字符串。這個處理過程也可以通過設置processData選項為false來回避。 |
|||||||||||||
processData |
(默認: true) 默認情況下,發送到服務器的數據(即data參數)將被轉換為字符串以配合默認內容類型 "application/x-www-form-urlencoded"。如果要發送 DOM 樹信息或其它不希望轉換的信息,請設置為 false。 jQuery中的處理方式: if ( s.data&&s.processData&&typeofs.data !== "string" ) { s.data = jQuery.param(s.data, s.traditional ); } |
|||||||||||||
async |
(默認: true) 默認設置下,所有請求均為異步請求。如果需要發送同步請求,請將此選項設置為 false。注意,同步請求將鎖住瀏覽器,用戶其它操作必須等待請求完成才可以執行。 |
|||||||||||||
timeout |
設置請求超時時間(毫秒)。通過setTimeout(fn,time)實現。 |
|||||||||||||
cache |
(默認: true)dataType為 script 和jsonp時默認為 false。設置為 false 將不緩存此頁面。 當使用GET或HEAD方式發送請求時要添加時間戳參數 (net Date()).getTime() 來保證每次發送的URL不同, 可以避免瀏覽器緩存.(只有GET和HEAD方式的請求瀏覽器才會緩存) jQuery中的處理方式: if ( s.cache === false ) { var ts = jQuery.now(), // rts = /([?&])_=[^&]*/嘗試替換 ret = s.url.replace( rts, "$1_=" + ts ); // rquery = /\?/如果沒有替換任何內容,則把時間戳加到url最后 s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" ); } 示例:/AjaxHandler.ashx?func=GetBinaryData&_=1368424995535 |
|||||||||||||
ifModified |
(默認: false) 僅在服務器數據改變時獲取新數據。通過響應頭If-Modified-Since、IF-None-Match和請求頭Last-Modified、Etag提高GET或HEAD方式請求效率。(只有GET和HEAD方式的請求瀏覽器才會緩存) |
|||||||||||||
global |
(默認: true) 是否觸發全局 AJAX 事件。設置為 false 將不會觸發全局AJAX 事件:ajaxStart、ajaxSend、ajaxSuccess、ajaxError、ajaxComplete、ajaxStop。(比如請求頻繁時可禁用全局AJAX事件提高效率) |
|||||||||||||
context |
(默認:true) 這個對象用於設置Ajax相關回調函數的上下文,讓回調函數內this指向這個對象。如果不設定這個參數,那么回調函數中的this就指向調用本次AJAX請求時傳遞的options參數載體“s對象”。但對於全局Ajax事件來說,this都是指向全局事件所綁定的元素。 |
|||||||||||||
jsonp |
指定獲得jsonp回調函數名的參數名(默認為:callback)。這個值用來替代URL中"callback=?"里的"callback"部分,比如{jsonp:'onJsonPLoad'}會替換為將"onJsonPLoad=?"傳給服務器。 |
|||||||||||||
jsonpCallback |
為jsonp請求指定一個回調函數名。jsonpCallback參數一般為字符串,也可接收函數(該函數返回字符串)。 默認情況下生成隨機函數名:"jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ) + jQuery.now() |
|||||||||||||
crossDomain |
(默認:null)false:同域請求;true跨域請求。 倘若crossDomain標識為null,則jQuery會自動根據本地url、端口來解析。可以根據需求直接賦值來提高性能。 通常情況下由服務器自動解析即可,但如果你想在同一域中強制跨域請求(像JSONP一樣),那么將crossDomain為true,這允許你將服務器端重定向到另一個域。 |
|||||||||||||
scriptCharset |
只有當請求時dataType為"jsonp"或"script",並且type是"GET"才會用於修改charset。 因為此時是動態創建<script>來完成腳本加載,但是如果js中的編碼與頁面的編碼不一致時,js可能加載失敗或者顯示亂碼或者IE下報某符號錯誤。設置此參數就相當於為<script>標簽設置charset屬性。 |
|||||||||||||
hearders |
(默認:{}) 設置HTTP請求頭數據"{鍵:值}"。此設置發生在:jQuery所有影響HTTP頭的參數(options)設置之后,beforeSend回調函數之前。 |
|||||||||||||
statusCode |
(默認:{}) 定義一組HTTP狀態碼與回調函數的映射,當響應的狀態碼有匹配statusCode則會觸發對應回調函數。例如,如果響應狀態是404,將觸發以下警報: $.ajax({ statusCode: {404: function() { alert('page not found'); } }); |
|||||||||||||
traditional |
如果你想要用傳統的方式來序列化數據,那么就設置為true。請參考$.param()深度遞歸詳解。 |
|||||||||||||
xhrFields |
聲明附加到XMLHttpRequest對象的自定義“key-value”數組。例如,如果需要的話,你可以用它來設置跨域的withCredentials為true,即: xhrFields: { withCredentials: true } |
|||||||||||||
5個局部事件 |
beforeSend、dataFilter、success、error、complete。(詳見后面事件介紹部分) |
|||||||||||||
由ajax函數內部解析或內部提供 |
||||||||||||||
dataTypes |
由dataType按空格拆分所得。 |
|||||||||||||
isLocal |
根據協議確定當前url請求的是否為本地請求。 jQuery中定義默認值為: isLocal:/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/.test(/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/.exec(url)) |
|||||||||||||
hasContent |
非GET或HEAD請求為true,用於處理data和contentType參數。 |
|||||||||||||
contents |
一個"{類型字符串:正則表達式}"的對象,倘若dataTypes[0]為“*”時,用contents中的正則表達式去匹配contentType,匹配成功則用“類型字符串”覆蓋dataTypes[0]。 jQuery內部定義如下: contents: { xml: /xml/, html: /html/, json: /json/, script: /javascript|ecmascript/ } |
|||||||||||||
accepts |
瀏覽器能夠處理的媒體類型,其值取決於dataTypes[0]參數。 jQuery內部定義如下: accepts: { xml: "application/xml, text/xml", html: "text/html", text: "text/plain", json: "application/json, text/javascript", script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript", "*": allTypes // dataTypes[0]匹配不上時取此值 } |
|||||||||||||
responseFields |
jqXHR超集設置“數據類型:屬性”對應關系,在返回響應數據時,用於確定創建哪個屬性變量。 jQuery中定義如下: responseFields: { xml: "responseXML", text: "responseText" } |
|||||||||||||
converters |
存儲數據類型對應的轉換器,根據dataTypes獲取對應轉換器,用於對響應數據response進行處理。該處理發生在dataFilter回調函數之后。 converters: { "* text": window.String, "text html": true, "text json": jQuery.parseJSON, "text xml": jQuery.parseXML, "text script": function( text ) { jQuery.globalEval( text ); // 執行腳本 return text; } } |
|||||||||||||
2) jqXHR對象
為不同瀏覽器內置的XMLHttpRequest提供了一致的超集。對於XMLHttpRequest之外的傳輸機制,比如JSONP請求,jXHR對象也可以進行處理。
超集與真子集:
如果一個集合S2中的每一個元素都在集合S1中,且集合S1中可能包含S2中沒有的元素,則集合S1就是S2的一個超集。 S1是S2的超集,則S2是S1的真子集,反之亦然。
jqXHR對象我們常常使用如下成員,這些成員主要用於ajax的全局事件和局部事件,並且做為$.ajax()函數返回值返回。
jqXHR:{ readyState ,setRequestHeader: function( name, value ) ,getAllResponseHeaders: function() ,getResponseHeader: function( key ) ,overrideMimeType: function( type ) ,abort: function( statusText ) ,responseText ,responseXML }
另外,jqXHR的全部成員如下:
在圖中我們看到一些陌生的函數,比如:done()、fail()、promise()、isResolve()、isRejected()、then()、always()、progress()等,都是jQuery的deferred對象API。
開發網站的過程中,我們經常遇到某些耗時很長的javascript操作。其中,既有異步的操作(比如ajax讀取服務器數據),也有同步的操作(比如遍歷一個大型數組),它們都不是立即能得到結果的。
通常的做法是,為它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。但是,在回調函數方面,jQuery的功能非常弱。為了改變這一點,jQuery開發團隊就設計了deferred對象。
簡單說,deferred對象就是jQuery的回調函數解決方案。在英語中,defer的意思是"延遲",所以deferred對象的含義就是"延遲"到未來某個點再執行。 它解決了如何處理耗時操作的問題,對那些操作提供了更好的控制,以及統一的編程接口。
更專業的資源:jQuery的deferred對象詳解
jQuery框架中,伴隨Ajax請求會觸發若干事件,我們可以訂閱這些事件並在其中處理我們的邏輯。在jQuery中有兩種Ajax事件:局部事件和全局事件。
1) 局部事件(回調函數),在$.ajax()方法的options參數中聲明,可以用來設置請求數據和獲取、處理響應數據。
beforeSend |
該函數可在發送請求前修改XMLHttpRequest對象,如添加自定義 HTTP 頭。 簽名:function (jqXHR,s) { } 函數說明:傳入jqXHR、s對象 |
dataFilter |
在請求成功之后調用。若狀態碼為304(未修改)則不觸發此回調。 簽名:function (data, dataType) { return newData; } 函數說明:傳入返回的數據、"dataType"參數的值。並且必須返回新的數據傳遞給success回調函數 |
success |
請求成功時觸發。 簽名:function (data,statusText,jqXHR) { } 函數說明:傳入返回的數據、描述狀態的字符串”success”、jqXHR對象 |
error |
請求失敗時調用此函數。 簽名:function (jqXHR, textStatus, errorThrown) { } 函數說明:傳入jqXHR對象、描述狀態的字符串”error”、錯誤信息 |
complete |
請求完成后回調函數 (請求成功或失敗之后均調用) 簽名:function (jqXHR, textStatus) { } 函數說明:傳入jqXHR對象、描述狀態的字符串(可能值:"No Transport"、"timeout"、"notmodified"---304 "、"parsererror"、"success"、"error") |
定義方式例如:
$.ajax({ // ... beforeSend: function(){ // Handle the beforeSend event }, complete: function(){ // Handle the complete event } // ... });
2) 全局事件,每次Ajax請求都會觸發,它會向DOM中的所有元素廣播,你只需為DOM中任意元素bind好全局事件即會觸發(若綁定多次,則會依次觸發為事件注冊的回調函數)。
ajaxStart |
開始新的Ajax請求,並且此時jQuery對象上沒有其他ajax請求正在進行。 簽名:function(e) 函數說明:傳入事件對象 |
ajaxSend |
當一個Ajax請求開始時觸發 簽名:function(e,jqXHR,s) 函數說明:傳入事件對象、jqXHR、s對象 |
ajaxSuccess |
全局的請求成功 簽名:function(e,jqXHR,s,data) 函數說明:傳入事件對象、jqXHR、s對象、請求成功返回的相應數據 |
ajaxError |
全局的發生錯誤時觸發 簽名:function(e,jqXHR,s,errorData) 函數說明:傳入事件對象、jqXHR、s對象、請求失敗返回的錯誤信息 |
ajaxComplete |
全局的請求完成時觸發 簽名:function(e,jqXHR,s) 函數說明:傳入事件對象、jqXHR、s對象 |
ajaxStop |
當jQuery對象上正在進行Ajax請求都結束時觸發。 簽名:function(e) 函數說明:傳入事件對象 |
全局事件在jQuery中的聲明方式:
jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){ jQuery.fn[ o ] = function( f ){ return this.on( o, f ); }; });
所以我們可以使用下面兩種方式定義全局事件:
// 可以用bind來綁定,用unbind來取消綁定。 $("#loading").bind("ajaxSend", function(){ … }); 或者: $("#loading").ajaxStart(function(){ … });
3) ajax方法完整的事件流
4) 示例:$.ajax()觸發的事件(局部事件和全局事件)
// 全局事件 $("#div_event").ajaxStart(function (e) { doAddEvent4textarea('txt_event', '觸發ajaxStart回調函數'); }); $("#div_event").ajaxSend(function (e) { doAddEvent4textarea('txt_event', '觸發ajaxSend回調函數'); }); $("#div_event").ajaxSuccess(function (e, jqXHR, s, data) { doAddEvent4textarea('txt_event', '觸發ajaxSuccess回調函數'); }); $("#div_event").ajaxError(function (e, jqXHR, s, errorData) { doAddEvent4textarea('txt_event', '觸發ajaxError回調函數'); }); $("#div_event").ajaxComplete(function (e, jqXHR, s) { doAddEvent4textarea('txt_event', '觸發ajaxComplete回調函數'); }); $("#div_event").ajaxStop(function (e) { doAddEvent4textarea('txt_event', '觸發ajaxStop回調函數'); }); // 局部事件 function bindLocalEvent(e) { var textareaid = e.data.textareaid; var global = e.data.global; $.ajax('AjaxHandler.ashx?func=btn_nowTime_long', { type: 'get', dataType: 'text', global: global, cache: false, beforeSend: function (jqXHR, s) { doAddEvent4textarea(textareaid, '觸發beforeSend回調函數'); }, dataFilter: function (data, dataType) { doAddEvent4textarea(textareaid, '觸發dataFilter回調函數'); }, success: function (data, statusText, jqXHR) { doAddEvent4textarea(textareaid, '觸發success回調函數'); }, error: function (jqXHR, textStatus, errorThrown) { doAddEvent4textarea(textareaid, '觸發error回調函數'); }, complete: function (jqXHR, textStatus) { doAddEvent4textarea(textareaid, '觸發complete回調函數'); } }); } function doAddEvent4textarea(textareaid, txt) { var textarea = $("#" + textareaid); textarea.val(textarea.val() + '\r\n' + txt); }
效果圖:
5) $.ajax()方法的全局事件典型用例
你的頁面存在多個甚至為數不少的ajax請求,但是這些ajax請求都有相同的消息機制。ajax請求開始前顯示一個提示框,提示“正在讀取數據”;ajax請求成功時提示框顯示“數據獲取成功”;ajax請求結束后隱藏提示框。
a) 不使用全局事件的做法是:
給$.ajax()加上beforeSend、success、complete回調函數,在回調函數中加上處理提示框。
b) 使用全局事件的做法是:
$(document).ajaxStart(onStart) .ajaxComplete(onComplete) .ajaxSuccess(onSuccess); function onStart(event) { //..... } function onComplete(event, xhr, settings) { //..... } function onSuccess(event, xhr, settings) { //..... }
3. jQuery ajax相關函數
1) jQuery.ajaxSetup({ })
jQuery.ajax()函數中的所有的參數選項都可以通過jQuery.ajaxSetup()函數來全局設置默認值。
2) $.ajax()函數的封裝
a) $("").load(url [, params] [, callback])
請求遠程的HTML文件代碼(dataType: "html"),默認使用 GET 方式,如果傳遞了params參數則使用Post方式。在請求“成功”完成時將responseText屬性值插入至DOM中。但不管請求是否成功完成“在最后”都會執行callback回調函數(即:complete:callback)。
b) jQuery.get(url [, data] [, callback] [, type] )
通過HTTP GET請求載入數據,並在請求成功時執行回調函數(即:success: callback)。
c) jQuery.getJSON(url [, data] [, callback] )
通過 HTTP GET 請求載入 JSON 數據。相當於: jQuery.get(url, [data],[callback], "json")
可以通過使用JSONP 形式的回調函數來加載其他網域的JSON數據。
d) jQuery.getScript(url [, callback] )
通過 HTTP GET 請求載入並執行一個 JavaScript 文件。相當於: jQuery.get(url, null, [callback], "script")
可以跨域調用 JavaScript 文件。
e) jQuery.post(url [, data] [, callback] [, type] )
通過 HTTP POST 請求載入信息,並在請求成功時執行回調函數(即:success: callback)。
3) 對象序列化
a) jQuery.param(object,traditional)
創建數組或對象的序列化表示,該序列化可在ajax請求時在URL查詢字符串中使用。
序列化過程中會使用encodeURIComponent()函數把字符串作為URI組件進行編碼。
encodeURIComponent() 方法不會對 ASCII 字母和數字進行編碼,也不會對這些 ASCII 標點符號進行編碼: - _ . ! ~ * ' ( ) 。其他字符(比如:;/?:@&=+$,# 這些用於分隔 URI 組件的標點符號),都是由一個或多個十六進制的轉義序列替換的。
// 在param中會進行如下處理 function( key, value ) { // 如果value是函數,則取其函數返回值 value = jQuery.isFunction( value ) ? value() : value; s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); };
對於 jQuery 1.4,$.param() 方法將會通過深度遞歸的方式序列化對象,以便符合現代化腳本語言的需求,比如 PHP、Ruby on Rails 等。你可以傳遞traditional = true 或在ajax功能中傳遞包含traditional的options參數。
傳送門:$.param()深度遞歸詳解和$.param() 示例
b) $("").serializeArray()
可以將一個或多個表單元素(比如 input、 textarea等),或者 form 元素本身的jQuery對象序列化為JSON對象。(非 JSON 字符串。需要使用插件或者第三方庫進行字符串化操作)
特別說明,元素不能被禁用(禁用的元素不會被包括在內),並且元素應當有含有 name 屬性。提交按鈕的值也不會被序列化。文件選擇元素的數據也不會被序列化。
c) $("").serialize()
可以將一個或多個表單元素(比如 input、 textarea等),或者 form 元素本身的jQuery對象序列化為經過URL編碼轉換后的字符串,可直接用在URL查詢字符串中。
jQuery內部定義:
serialize: function() { return jQuery.param( this.serializeArray() ); }
$.ajax()中常見應用示例
1) cache參數:GET和POST最重要的區別(傳送門)
語義上,GET是獲取指定URL上的資源,是讀操作,重要的一點是不論對某個資源GET多少次,它的狀態是不會改變的,在這個意義上,我們說GET是安全的(不是被密碼學或者數據保護意義上的安全)。因為GET是安全的,所以GET返回的內容可以被瀏覽器,Cache服務器緩存起來。
而POST的語意是對指定資源“追加/添加”數據,所以是不安全的,每次提交的POST,參與的代碼都會認為這個操作會修改操作對象資源的狀態,於是,瀏覽器在你按下F5的時候會跳出確認框,緩存服務器不會緩存POST請求返回內容。
2) ifModified參數:通過ifModified參數提高請求性能(即:“條件GET”:Last-Modified / If-Modified-Since和ETag / If-None-Match)
當你請求的資源並不是一層不變的時候,即不能簡單的一直使用客戶端緩存時,你可能通過將cache設置為false來發送請求,這實際上是在url加上時間戳組合成新的url,每次發送新的請求,這明顯加大了服務器的壓力。
對於這種情況,我們可以通過ifModified參數改進緩存方式(即:cache和ifModified都設置為true),僅在請求的數據改變時重新獲取。通過這種方式請求的url不會改變,並且每次都會發送到服務器,只是會有檢驗方法驗證是否需要重新獲取數據從而節省帶寬和開銷。
更多ETag描述(優點,解決了Last-Modified無法解決的一些問題,什么場合不應該被使用)
過程如下:
a) 將$.ajax()函數的cache和ifModified參數同時設置為true。
b) 客戶端請求服務端A,在服務端加上Last-Modified/ETag響應體一起返回。
c) 客戶端緩存接收到的Last-Modified/ETag響應體,並在下一次發生請求A時將緩存的Last-Modified/ETag值做為If-Modified-Since/IF-None-Match請求頭一起發給服務器。
d) 服務器接收If-Modified-Since/IF-None-Match后,就根據參數值檢驗自上次客服端請求之后資源是否有改動
i. 若還未改動則直接返回響應304和一個空的響應體。
ii. 若已改動則重新處理數據,返回最新的請求數據。
e) 這樣,既保證不向客戶端重復發出資源,也保證當服務器有變化時,客戶端能夠得到最新的資源。
這一過程中,我們只需要做:服務器返回Last-Modified/ETag響應頭和在服務端檢驗數據是否失效並采取對應處理方式。其余步驟由jQuery框架的ajax()函數完成。
關鍵代碼如下:
客服端:
$('#btn_nowTime_long3').bind('click', null , function () { $.ajax('AjaxHandler.ashx?func=GetServerTime4Modified', { type: 'get', dataType: 'text', cache: true, ifModified: true, success: function (data) { if (data) alert(data); }, }); });
服務端:
if(!String.IsNullOrEmpty(context.Request.Headers["If-Modified-Since"])) { if (CheckResourceValidate()) // 檢查資源有效性 { // 如果資源有效,則直接返回304狀態碼,客戶端回去到此狀態碼后會從緩存中取值。 context.Response.StatusCode = 304; return; } } // 請求數據 GetServerTimeAfter2Second(); context.Response.Cache.SetExpires(DateTime.Now.AddSeconds(5)); // 設置Last-Modified響應體 context.Response.Cache.SetLastModified(DateTime.Now);
在JavaScript中,有一個很重要的安全性限制,被稱為“Same-Origin Policy”(同源策略)。這一策略對於JavaScript代碼能夠訪問的頁面內容做了很重要的限制,即JavaScript只能訪問與包含它的文檔在同一域下的內容。所謂同源是指,域名(host),協議(protocol),端口(port)相同。
URL |
說明 |
是否允許通信 |
能否通過javascript解決 |
http://www.a.com/a.js http://www.a.com/b.js |
同一域名下 |
允許 |
|
http://www.a.com/lab/a.js http://www.a.com/script/b.js |
同一域名下不同文件夾 |
允許 |
|
http://www.a.com:8000/a.js http://www.a.com/b.js |
同一域名,不同端口 |
不允許 |
能 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名,不同協議(http和https) |
不允許 |
不能 |
http://www.a.com/a.js http://70.32.92.74/b.js |
不允許 |
能 |
|
http://www.cnblogs.com/a.js http://www.a.com/b.js http://script.a.com/b.js http://a.com/b.js |
不同域名(host) |
不允許 |
能 |
注:一級域名與二級域名之間;不同二級域名之間 都屬於不同域名
1) $.ajax()為我們提供了兩種解決方案,不過都是只支持get方式,分別是jQuery的jQuery.ajax“jsonp”格式和jquery.getScript()(即jQuery.ajax “script”格式)方式。
2) $.ajax()跨域原理分析
由於javascript的安全限制“同源策略”,所以我們無法使用XMLHttpRequest直接請求別的域名下的資源。不過擁有src屬性和href屬性的<script>\<img>\<iframe>和<link>\<a>標簽不受同源策略影響。$.ajax()提供的兩種解決方案正是應用了動態創建<script>的方式來實現(即:生成<script>標簽,src引入腳本,然后執行,最后移除<script>標簽)。
3) jQuery.ajax()的jsonp和script方式的異同點:
a) 相同:都走$.ajax() script格式的流程;不會觸發全局事件和局部事件;只支持GET方式(POST請求會自動轉化為GET請求);默認不啟用緩存(cache:false)
b) 不同:jsonp方式可以通過jsonp和jsonpCallback參數指定一個特定回調函數。
4) 示例部署說明:
因為是跨域請求,所以需要在本機部署兩個示例程序以模擬不同域之間的訪問,並且在示例代碼中需要修改“crossUrl”為目的域路徑。
5) jsonp示例代碼:
客服端:
// jsonp方式跨域請求(dataType:jsonp) $('#btn_cross_req1').bind('click', null , function () { $.ajax(crossUrl, { type: 'get', dataType: 'jsonp', jsonp: 'jsonpParamName', jsonpCallback: 'crossCallback', crossDomain: true, }); }); function crossCallback(data) { alert('jsonp' + data); }
服務端:
context.Response.ContentType = "text/plain"; string jsonpCallbackName = reqCollection["jsonpParamName"]; context.Response.Write(String.Format("{0}('來自域:{1}的相應信息')" , jsonpCallbackName, context.Request.Url.Host));
分析:
a) 因jsonp和jsonpCallback參數而改變的url如下。(即默認為:callback=jQuery隨機值,更改為:jsonpParamName=crossCallback)
URL:http://192.168.1.100:6567/AjaxHandler.ashx?func=CrossRequest&jsonpParamName=crossCallback&_=1368360234428
b) 服務器端獲取到jsonp回調函數名后,返回一個函數表達式。
6) 在XMLHttpRequest Level 2中新增了跨域訪問方式、接收二進制等新功能,詳細請看:XMLHttpRequest2 新技巧
最后,再來一張示例截圖吧!!!
本篇博文到此結束,主要介紹內容是使用XMLHttpRequest實現ajax請求和XMLHttpRequest Level 2為我們所帶來的改進,最后重點講解了jQuery中通過$.ajax()方法實現ajax以及各個參數的詳細介紹,並立舉了經典示例說明了:跨域請求、ajax全局事件、ajax局部事件、xhr二進制數據處理、如何高效使用緩存……
做為一個后台工程師,你是否想深入了解一些前台必須的技術呢?是的,我想了解,並且會慢慢把所了解到的技術以博文的方式整理分享給大家。
謝謝大家查閱,如果覺得文章不錯,還請多多幫推薦……
文中出現比較多的相關資源鏈接,這里整理下方便大家日后快速找到鏈接:
1) jQuery相關
這是有關 Ajax 編程模型信息的一站式中心,包括很多文檔、教程、論壇、blog、wiki 和新聞。任何 Ajax 的新信息都能在這里找到。
jQuery.ajax()中的預過濾器和分發機制函數inspectPrefiltersOrTransports詳解
2) XMLHttpRequest Level 2 的新功能相關
3) 跨域請求相關
總結了5種js跨域方式:利用<iframe>標簽和document.domain屬性、動態創建scrip、利用<iframe>標簽和location.hash屬性、window.name實現的跨域數據傳輸、使用HTML5 postMessage、利用flash跨域。
4) HTTP相關
1) 介紹了一次HTTP通信的7個步驟:建立TCP連接、Web瀏覽器向Web服務器發送請求命令、Web瀏覽器發送請求頭信息、Web服務器應答、Web服務器發送應答頭信息、Web服務器向瀏覽器發送數據、Web服務器關閉TCP連接
2) 介紹HTTP請求格式
格式:Content-Type: [type]/[subtype]; parameter
5)Jquery其他部分