轉載請標明出處
本文出自HCY的博客
Ajax是“Asynchronous javascript And xml”的縮寫,中文譯作“異步Javascript和XML”。使用AJAX可以通過HTTP協議與服務器交互數據,可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。 傳統的網頁如果需要更新內容,必須重新加載整個網頁頁面。此外,它也是實現前端與后端解耦的重要技術手段。
為了實現AJAX技術,早期微軟的IE5、IE6瀏覽器內嵌了xmlhttp組件,其它瀏覽器比如Opera、Mozila的早期版本則內嵌了XMLHttPRequest組件。XMLHTTP與XMLHttpRequest有很多相同的屬性和方法,因此XMLHTTP也被一起叫做XMLHttpRequest,簡稱XHR。后來XHR被W3C組織標準化。各瀏覽器也逐漸按照W3C制定的標準來實現XHR,到目前為止,仍然有部分的屬性和方法不被部分瀏覽器支持。下面的圖片截取于 Can I Use網站,它描述了目前各瀏覽器對XHR的兼容情況。因此,在使用XHR開發時需要注意兼容性,不過筆者認為,老版本瀏覽器的占有量會越來越少,新版本的瀏覽器可能會更加嚴格的按照W3C制定的標準來實現XHR,兼容性問題就會被慢慢淡化,Jquery框架在2.2的版本在實例化XHR時就不考慮IE5、IE6的兼容性問題了。
為了實現兼容IE5、IE6瀏覽器版本,所以可以用下面的代碼創建XHR實例。
var xhr;if (window.XMLHttpRequest){ // IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執行代碼 xhr=new XMLHttpRequest();}else{ // IE6, IE5 瀏覽器執行代碼 xhr=new ActiveXObject("Microsoft.XMLHTTP");}XHR可以通過HTTP協議與服務器交換數據,要發送HTTP請求要使用到下面這些方法和屬性:
open方法用于創建HTTP請求,但是請求并未發送,其定義如下:
open(method, url [, async = true [, username = null [, passWord = null]]])參數method定義請求的類型,如GET、POST方法等等,大小寫不敏感參數url定義請求的URL地址參數async定義是否異步處理請求,true(異步)或者false(同步),默認為true參數username定義用戶名,不常用,默認為null參數password定義密碼,不常用,默認為nullsetRequestHeader方法用于向請求添加HTTP頭,其定義如下:
setRequestHeader(name, value)參數name定義HTTP請求頭部的名稱參數value定義HTTP請求頭部的值注意: 1. setRequestHeader方法必須在open方法調用之后、send方法之前調用,否則會出現異常 2. setRequestHeader方法可以連續調用多次,如果已經存在同名的HTTP頭時,最終結果是追加而不是覆蓋
//例子1client.setRequestHeader('X-Test', 'one');client.setRequestHeader('X-Test', 'two');//最后的結果為X-Test: one, two//例子2client.setRequestHeader('X-Test', 'one');client.setRequestHeader('X-Test', 'one');//最后的結果為X-Test: one, onetimeout屬性用于設置HTTP請求的超時時間,單位毫秒。當發生超時時,會觸發ontimeout事件。在IE中,超時屬性只能在調用 open() 方法之后且在調用 send() 方法之前設置。
upload用于在數據傳輸到服務器時收集一些傳輸信息,比如上傳了多少字節,總共多少字節等,其里面還包含了一些事件回調。
send方法用于發送open方法創建的HTTP請求,其定義如下:
send([body = null])參數body定義HTTP請求的數據,當HTTP請求的方法為GET、HEAD時,該參數被忽略。body的類型可以為ArrayBuffer(二進制緩沖數組)、Blob(二進制大對象)、Document(類似XML格式的數據)、DOMString(字符串)、FormData(表單)。上面幾種數據類型的介紹可參考:
ArrayBuffer、Blob、Document、DOMString、FormData類型的數據介紹
當請求發送后如果想終止這個請求,則可以調用abort方法,其定義如下:
abort()當XHR發送異步請求后,我們無法知道請求是否發生了異常、請求何時到達服務器、服務器何時返回響應數據。XHR為我們提供了很多的事件回調,用來通知我們請求及響應狀態的改變。下面的接口定義語言描述了跟XHR相關的事件接口定義。
interface XMLHttpRequestEventTarget : EventTarget { // event handlers attribute EventHandler onloadstart; attribute EventHandler onprogress; attribute EventHandler onabort; attribute EventHandler onerror; attribute EventHandler onload; attribute EventHandler ontimeout; attribute EventHandler onloadend;};interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {};interface XMLHttpRequest : XMLHttpRequestEventTarget { // event handler attribute EventHandler onreadystatechange; // states //XHR的狀態定義 const unsigned short UNSENT = 0; const unsigned short OPENED = 1; const unsigned short HEADERS_RECEIVED = 2; const unsigned short LOADING = 3; const unsigned short DONE = 4; //用于描述XHR的狀態 readonly attribute unsigned short readyState; // request [SameObject] readonly attribute XMLHttpRequestUpload upload;};readyState屬性用于描述XHR的狀態,它有下面五種狀態:值 | 狀態 | 描述 |
---|---|---|
0 | UNSENT | 最初始狀態,還未調用open方法 |
1 | OPENED | 已經調用了open方法 |
2 | HEADERS_RECEIVED | 已經調用了send方法,響應的HTTP頭部和狀態可以獲取 |
3 | LOADING | 正在下載數據,下載的數據還不完整 |
4 | DONE | 數據下載完成 |
- onreadystatechange屬性可以指定一個回調函數,當XHR的狀態(即readyState)發生改變時就會調用該函數,可以在這個回調函數中判斷請求是否成功。
xhr.onreadystatechange = function() { if (xhr.readyState == 4) { //當XHR的狀態為4時判斷請求成功與否,然后處理響應的數據,雖然當XHR的狀態為2或者3時可以獲取到響應狀態,但是此時的數據還未下載完全,不能處理響應數據 if (xhr.status == 200) { //請求成功,處理響應數據 } else { //請求失敗 } } }upload屬性代表上傳數據的過程,它是XMLHttpRequestUpload的實例,XMLHttpRequestUpload繼承XMLHttpRequestEventTarget接口,XMLHttpRequestEventTarget有7個回調方法,在數據上傳的過程中會調用相應的方法。XHR也繼承XMLHttpRequestEventTarget接口,因此它也擁有這些回調方法,但是它的回調方法大多都是從服務器下載響應數據的過程中觸發的。upload的回調方法會在數據上傳的過程中觸發,XHR的回調方法大多在響應數據下載的過程中觸發,具體的觸發時機見下表:
事件 | 觸發時機 |
---|---|
onreadystatechange | 當readyState的值改變時觸發,除了當它從非0變成0時 |
onloadstart | 當調用send方法時會觸發xhr.onloadstart,然后會觸發xhr.upload.onloadstart,代表開始上傳數據 |
onprogress | 上傳數據過程中會觸發xhr.upload.onprogress,下載數據過程中會觸發xhr.onprogress,onprogress每50ms會觸發一次 |
onabort | 調用abort方法后會觸發 |
onerror | 當發生網絡異常的時候會觸發,如果上傳數據的過程還未結束,此時會先觸發xhr.upload.onerror,然后再觸發xhr.onerror;如果上傳數據的過程已經結束,此時只會觸發xhr.onerror |
onload | 上傳數據成功,會觸發xhr.upload.onload;下載數據成功會觸發xhr.onload |
ontimeout | 當服務端響應的時間超過指定的timeout時間時,會觸發此事件 |
onloadend | 上傳數據完成(成功或者失?。r會觸發xhr.upload.onloadend;下載數據完成(成功或失?。|發xhr.onloadend |
通過下面的代碼驗證,可以得出事件觸發的順序。
var xhr = new XMLHttpRequest(); xhr.timeout = 1; //xhr events xhr.onreadystatechange = function() { console.log("onreadystatechange(),readyState=" + xhr.readyState); } xhr.onloadstart = function(event) { console.log("onloadstart()"); } xhr.onprogress = function(event) { console.log("onprogress()"); } xhr.onabort = function(event) { console.log("onabort()"); } xhr.onerror = function(event) { console.log("onerror()"); } xhr.onload = function(event) { console.log("onload()"); } xhr.ontimeout = function(event) { console.log("ontimeout()"); } xhr.onloadend = function(event) { console.log("onloadend()"); } //upload events xhr.upload.onloadstart = function(event) { console.log("upload.onloadstart()"); } xhr.upload.onprogress = function(event) { console.log("upload.onprogress()"); } xhr.upload.onabort = function(event) { console.log("upload.onabort()"); } xhr.upload.onerror = function(event) { console.log("upload.onerror()"); } xhr.upload.onload = function(event) { console.log("upload.onload()"); } xhr.upload.ontimeout = function(event) { console.log("upload.ontimeout()"); } xhr.upload.onloadend = function(event) { console.log("upload.onloadend()"); } try { xhr.open("POST", "http://localhost:8080/Server/test", true); xhr.send("hello"); } catch (e) { alert(e.toString()); }打印的順序如下:
//調用了open方法onreadystatechange(),readyState=1//調用了send方法onloadstart()//上傳數據過程中的事件回調upload.onloadstart()//開始上傳請求數據upload.onprogress()//正在上傳請求數據upload.onload()//成功上傳請求數據upload.onloadend()//完成上傳請求數據//下載響應數據過程中的事件回調onreadystatechange(),readyState=2//已經獲取到響應頭部和響應狀態碼onreadystatechange(),readyState=3//正在下載響應數據,改變狀態onprogress()//正在下載響應數據onreadystatechange(),readyState=4//響應數據下載完成,改變狀態onload()//成功下載響應數據onloadend()//完成下載響應數據XMLHttpRequestEventTarget里面的回調方法的參數類型為ProgressEvent,ProgressEvent的定義如下:
interface ProgressEvent : Event { readonly attribute boolean lengthComputable;//數據長度是否可計算的 readonly attribute unsigned long long loaded;//已經下載或者上傳了多少字節 readonly attribute unsigned long long total;//需要下載或者上傳的總字節數};所以在onprogress方法回調中,可以通過loaded和total這兩個屬性來實現上傳或者下載的進度條功能。
因此下面的代碼實現的效果與方式一相同
xhr.addEventListener("loadstart", function(event) { console.log("loadstart()"); });了解了XHR的請求、XHR的事件回調之后,就剩下處理XHR響應的工作了,比如解析數據等等,要處理響應,需要了解下面的方法和屬性。
getResponseHeader方法可以獲取HTTP響應頭指定鍵值的數據,其定義如下:
getResponseHeader(ByteString name);參數name為HTTP響應頭部的鍵值getAllResponseHeaders方法可以獲取所有的HTTP響應頭的數據,其定義如下:
getAllResponseHeaders()status屬性表示HTTP響應狀態碼,即200、404等;statusText屬性表示HTTP響應狀態的描述文本,即OK、Not Found等。
可以在發送請求之前設置responseType,用于指定返回的響應數據的類型,responseType的類型有以下幾種:
類型 | 描述 |
---|---|
empty string | 空字符串,這是默認值 |
arraybuffer | 二進制緩沖數組 |
blob | 二進制大對象 |
document | 文檔類型 |
json | JSON類型 |
text | 文本類型 |
處理響應數據時,需要根據responseType來判斷返回的數據類型。當responseType為text或者empty string類型時可以使用responseText屬性,為其它類型時調用responseText會發生異常;當responseType為document或者empty responseXML屬性,為其它類型時調用responseXML會發生異常;當responseType不是empty string、text、document類型時,需要轉換成具體的類型進行解析。
通過XHR回調事件的觸發時機我們可以知道,onreadystatechange回調會觸發多次,因此方式二更優。
掃一掃關注我的公眾號。
新聞熱點
疑難解答