【转】4.1触碰jQuery:AJAX异步详解
傳送門:異步編程系列目錄……
示例源碼:觸碰jQuery:AJAX異步詳解.rar
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封裝:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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); ????????????????} ????????????} ????????} ????} } |
使用:
| 1 2 3 4 5 6 7 8 9 | $('#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,將服務器返回的二進制數據偽裝成文本數據,并且告訴瀏覽器這是用戶自定義的字符集。
關鍵代碼如下:
服務端
| 1 2 3 4 5 6 7 8 9 10 11 | ????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); |
客服端
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | $('#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,表示服務器傳回的是二進制對象。
| 1 2 3 | var?xhr = new?XMLHttpRequest(); xhr.open ('GET', '/path/to/image.png'); xhr.responseType = 'blob'; |
接收數據的時候,用瀏覽器自帶的?Blob?對象即可。注意,讀取的xhr.response,而不是xhr.responseText。
| 1 | var?blob = new?Blob ([xhr.response], {type: 'image/png'}); |
還可以將responseType設為arraybuffer,把二進制數據裝在一個數組里。然后再遍歷這個數組。
| 1 2 3 4 5 6 7 8 9 10 | 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新功能描述請看:
1)???XMLHttpRequest?增強功能
2)???XMLHttpRequest Level 2?使用指南
3)???XMLHttpRequest2?新技巧
?
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?也可以使用,但僅部分瀏覽器支持。 | |||||||||||||
| dataType | 預期服務器返回的數據類型。如果不指定,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中的處理方式:
| |||||||||||||
| async | (默認: true)?默認設置下,所有請求均為異步請求。如果需要發送同步請求,請將此選項設置為?false。注意,同步請求將鎖住瀏覽器,用戶其它操作必須等待請求完成才可以執行。 | |||||||||||||
| timeout | 設置請求超時時間(毫秒)。通過setTimeout(fn,time)實現。 | |||||||||||||
| cache | (默認: true)dataType為?script?和jsonp時默認為?false。設置為?false?將不緩存此頁面。 當使用GET或HEAD方式發送請求時要添加時間戳參數?(net Date()).getTime()?來保證每次發送的URL不同,?可以避免瀏覽器緩存.(只有GET和HEAD方式的請求瀏覽器才會緩存) jQuery中的處理方式:
示例:/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,將觸發以下警報:
| |||||||||||||
| traditional | 如果你想要用傳統的方式來序列化數據,那么就設置為true。請參考$.param()深度遞歸詳解。 | |||||||||||||
| xhrFields | 聲明附加到XMLHttpRequest對象的自定義“key-value”數組。例如,如果需要的話,你可以用它來設置跨域的withCredentials為true,即: xhrFields: { withCredentials: true }?? | |||||||||||||
| 5個局部事件 | beforeSend、dataFilter、success、error、complete。(詳見后面事件介紹部分) | |||||||||||||
| ? 由ajax函數內部解析或內部提供 | ||||||||||||||
| dataTypes | 由dataType按空格拆分所得。 | |||||||||||||
| isLocal | 根據協議確定當前url請求的是否為本地請求。 jQuery中定義默認值為:
| |||||||||||||
| hasContent | 非GET或HEAD請求為true,用于處理data和contentType參數。 | |||||||||||||
| contents | 一個"{類型字符串:正則表達式}"的對象,倘若dataTypes[0]為“*”時,用contents中的正則表達式去匹配contentType,匹配成功則用“類型字符串”覆蓋dataTypes[0]。 jQuery內部定義如下:
| |||||||||||||
| accepts | 瀏覽器能夠處理的媒體類型,其值取決于dataTypes[0]參數。 jQuery內部定義如下:
| |||||||||||||
| responseFields | jqXHR超集設置“數據類型:屬性”對應關系,在返回響應數據時,用于確定創建哪個屬性變量。 jQuery中定義如下:
| |||||||||||||
| converters | 存儲數據類型對應的轉換器,根據dataTypes獲取對應轉換器,用于對響應數據response進行處理。該處理發生在dataFilter回調函數之后。
| |||||||||||||
| ? | ? | ? | ||||||||||||
2)???jqXHR對象
為不同瀏覽器內置的XMLHttpRequest提供了一致的超集。對于XMLHttpRequest之外的傳輸機制,比如JSONP請求,jXHR對象也可以進行處理。
超集與真子集:
如果一個集合S2中的每一個元素都在集合S1中,且集合S1中可能包含S2中沒有的元素,則集合S1就是S2的一個超集。?S1是S2的超集,則S2是S1的真子集,反之亦然。
????jqXHR對象我們常常使用如下成員,這些成員主要用于ajax的全局事件和局部事件,并且做為$.ajax()函數返回值返回。
| 1 2 3 4 5 6 7 8 9 10 | 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對象詳解
?
2.???jQuery Ajax事件
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") |
????????定義方式例如:
| 1 2 3 4 5 6 7 8 9 10 | $.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中的聲明方式:
| 1 2 3 4 5 | jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " "?), function( i, o ){ ????????jQuery.fn[ o ] = function( f ){ ????????return?this.on( o, f ); ????}; }); |
????所以我們可以使用下面兩種方式定義全局事件:
| 1 2 3 4 | // 可以用bind來綁定,用unbind來取消綁定。 $("#loading").bind("ajaxSend", function(){ … }); 或者: $("#loading").ajaxStart(function(){ … }); |
3)???ajax方法完整的事件流
????
????
4)???示例:$.ajax()觸發的事件(局部事件和全局事件)
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | // 全局事件 $("#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)???使用全局事件的做法是:
| 1 2 3 4 5 6 | $(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?組件的標點符號),都是由一個或多個十六進制的轉義序列替換的。
| 1 2 3 4 5 6 | // 在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?屬性。提交按鈕的值也不會被序列化。文件選擇元素的數據也不會被序列化。
???????????傳送門:$("").serializeArray()?示例
c)???$("").serialize()
可以將一個或多個表單元素(比如?input、?textarea等),或者?form?元素本身的jQuery對象序列化為經過URL編碼轉換后的字符串,可直接用在URL查詢字符串中。
???????jQuery內部定義:
| 1 2 3 | serialize: function() { ????return?jQuery.param( this.serializeArray() ); } |
傳送門:$("").serialize()示例
?
$.ajax()中常見應用示例
1.???cache和ifModified參數
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()函數完成。
關鍵代碼如下:???
客服端:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $('#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); ?????????????????}, ?????????}); ?}); |
服務端:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); |
2.???跨域請求
在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 | 域名和域名對應ip | 不允許 | 能 |
| 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示例代碼:
客服端:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ????// 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); } |
????????服務端:
| 1 2 3 4 | 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?新技巧
?
最后,再來一張示例截圖吧!!!
示例源碼:觸碰jQuery:AJAX異步詳解.rar
?
?
?
?
?
本篇博文到此結束,主要介紹內容是使用XMLHttpRequest實現ajax請求和XMLHttpRequest Level 2為我們所帶來的改進,最后重點講解了jQuery中通過$.ajax()方法實現ajax以及各個參數的詳細介紹,并立舉了經典示例說明了:跨域請求、ajax全局事件、ajax局部事件、xhr二進制數據處理、如何高效使用緩存……
做為一個后臺工程師,你是否想深入了解一些前臺必須的技術呢?是的,我想了解,并且會慢慢把所了解到的技術以博文的方式整理分享給大家。
謝謝大家查閱,如果覺得文章不錯,還請多多幫推薦……
?
?
?
?
文中出現比較多的相關資源鏈接,這里整理下方便大家日后快速找到鏈接:
1)???jQuery相關
????????jQueryAPI文檔
????????jQuery百度百科(Eg:模塊,歷史版本)
Ajax?技術資源中心(IBM)
這是有關?Ajax?編程模型信息的一站式中心,包括很多文檔、教程、論壇、blog、wiki?和新聞。任何?Ajax?的新信息都能在這里找到。
jQuery.ajax()中的預過濾器和分發機制函數inspectPrefiltersOrTransports詳解
jQuery的deferred對象詳解
$.param()深度遞歸詳解
2)???XMLHttpRequest Level 2?的新功能相關
????????XMLHttpRequest?增強功能
????????XMLHttpRequest Level 2?使用指南
????????XMLHttpRequest2?新技巧
3)???跨域請求相關
JavaScript跨域總結與解決辦法
總結了5種js跨域方式:利用<iframe>標簽和document.domain屬性、動態創建scrip、利用<iframe>標簽和location.hash屬性、window.name實現的跨域數據傳輸、使用HTML5 postMessage、利用flash跨域。
域名和IP地址及域名解析
xhr注入_百度百科
????????說說JSON和JSONP
4)???HTTP相關
HTTP深入淺出 http請求
1)???介紹了一次HTTP通信的7個步驟:建立TCP連接、Web瀏覽器向Web服務器發送請求命令、Web瀏覽器發送請求頭信息、Web服務器應答、Web服務器發送應答頭信息、Web服務器向瀏覽器發送數據、Web服務器關閉TCP連接
2)???介紹HTTP請求格式
????????HTTP GET和POST的區別
HTTP?頭部詳解
????????HTTP Content-type對照表
????????格式:Content-Type: [type]/[subtype]; parameter
????????HTTP狀態碼一覽表(HTTP Status Code)???
? ? 5)Jquery其他部分
? ? ? ??不定義JQuery插件,不要說會JQuery
?
?
作者:滴答的雨
出處:http://www.cnblogs.com/heyuquan/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
總結
以上是生活随笔為你收集整理的【转】4.1触碰jQuery:AJAX异步详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再见!罗永浩微博正式更名交个朋友直播间
- 下一篇: AMD RX 6700新卡刀法砍歪了:性