Ajax和XMLHttpRequest
Ajax:"Asynchronous JavaScript And XML"即異步JavaScript和XML,是一種創(chuàng)建交互式網(wǎng)頁應(yīng)用的網(wǎng)頁開發(fā)技術(shù),這項(xiàng)技術(shù)的核心是瀏覽器提供的XMLHttpRequest對象。
XMLHttpRequest的使用
1.設(shè)置request header
void setRequestHeader(headerName, headerValue)
- setRequestHeader必須寫在open()方法之后,send()方法之前
2. 獲取response header
getAllResponseHeaders()
- 獲取全部可獲?。ㄓ幸恍﹉eader是獲取不到的)的header字段
getResponseHeader(headerName)
- 獲取指定header字段的值(只能獲取部分header的值)
3. 指定xhr.response的數(shù)據(jù)類型
- 通過設(shè)置
xhr.response的類型,是告訴瀏覽器或者xhr如何處理響應(yīng)數(shù)據(jù)(對響應(yīng)數(shù)據(jù)按照什么樣的格式去處理)
xhr.overrideMimeType()
- 這個(gè)方法的作用就是重寫response的MIME類型
- 這個(gè)方法必須在send()方法之前進(jìn)行調(diào)用
- 可以通過這種方式,可以得到純文本格式的圖片內(nèi)容,獲取到數(shù)據(jù)后再使用相應(yīng)的編碼方法重新構(gòu)建圖片
var xhr = new XMLHtppRequest()
xhr.open('get', 'text.php', true)
xhr.overrideMimeType("text/xml; charset=utf-8")
xhr.send();
根據(jù)上面的例子,將response的MIME類型設(shè)置為了'text/xml',通過這樣的方式,xhr會將響應(yīng)當(dāng)做text或者xml來處理,通過xhr.response和xhr.responseText可以獲取到文本格式的相應(yīng)數(shù)據(jù),通過xhr.responseXML可以獲取到XML格式(是一顆DOM樹/DOM對象)的數(shù)據(jù)
var xhr = new XMLHtppRequest()
xhr.open('get', 'text.php', true)
xhr.overrideMimeType("text/plain; charset=utf-8")
xhr.send();
根據(jù)上面的例子,將response的MIME類型設(shè)置為了'text/plain',通過這樣的方式,xhr會將相應(yīng)當(dāng)做text或者plain(純文本)來處理,通過xhr.response和xhr.responseText可以獲取到文本格式的相應(yīng)數(shù)據(jù),通過xhr.responseXML獲取到的數(shù)據(jù)為null,即便數(shù)據(jù)是XML
xhr.responseType
responseType是XMLHttpRequest leve2中新增的屬性,用來指定xhr.response的數(shù)據(jù)類型

var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
//可以將`xhr.responseType`設(shè)置為`"blob"`也可以設(shè)置為`" arrayBuffer"`
//xhr.responseType = 'arrayBuffer';
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
// this.response就是Blob對象
var blob = this.response;
...
}
};
xhr.send();
4. 如何獲取response數(shù)據(jù)
xhr提供了3個(gè)屬性來獲取請求返回的數(shù)據(jù),分別是:xhr.response, xhr.responseText, xhr.responseXML
-
xhr.response:- 無論
xhr.responseType的值是什么,只要請求完成,都可以從xhr.response中取到對應(yīng)的值 - 請求未完成時(shí),
xhr.response的值與xhr.responseType有關(guān),xhr.responseType的值為""(默認(rèn)值)或者text時(shí),xhr.response的值為"",否則為null
- 無論
-
xhr.responseText:- 只有當(dāng)responseType設(shè)置為
''或者text時(shí),才可以使用這個(gè)屬性獲取相應(yīng)內(nèi)容 - 請求未完成、失敗時(shí),該值為空字符串
- 只有當(dāng)responseType設(shè)置為
-
xhr.responseXML:- 只有當(dāng) responseType 為
''、document時(shí),此時(shí)才能調(diào)用xhr.responseXML,否則拋錯(cuò) - 請求未完成、失敗時(shí),該值為null
- 只有當(dāng) responseType 為
5. 如何追蹤ajax請求的當(dāng)前狀態(tài)
- 用
xhr.readyState屬性可以獲取ajax的狀態(tài),每當(dāng)xhr.readyState的值發(fā)生變化時(shí),就會觸發(fā)xhr.onreadystatechange事件,可以在這個(gè)事件中進(jìn)行相應(yīng)的操作 - 為了保證跨瀏覽器兼容性,必須在調(diào)用open()方法之前指定onreadystatechange事件處理程序
xhr.onreadystatechange = function () {
switch(xhr.readyState){
case 1://OPENED
//do something
break;
case 2://HEADERS_RECEIVED
//do something
break;
case 3://LOADING
//do something
break;
case 4://DONE
//do something
break;
}

6 設(shè)置請求的超時(shí)時(shí)間
- XMLHttpRequest提供了timeout屬性來允許設(shè)置請求的超時(shí)時(shí)間。
- 從請求開始 算起,若超過 timeout 時(shí)間請求還沒有結(jié)束(包括成功/失?。?,則會觸發(fā)ontimeout事件,主動結(jié)束該請求。
- 請求開始:xhr.onloadstart事件觸發(fā)的時(shí)候,也就是你調(diào)用xhr.send()方法的時(shí)候
- 請求結(jié)束:xhr.loadend事件觸發(fā)的時(shí)候。
7 發(fā)送同步請求
由open()方法的第三個(gè)參數(shù)決定,當(dāng)?shù)谌齻€(gè)參數(shù)async為true時(shí),發(fā)送異步請求,為false時(shí)則為同步請求
-
當(dāng)xhr為同步請求時(shí),有如下限制:
- xhr.timeout必須為0
- xhr.withCredentials必須為 false
- xhr.responseType必須為""(即默認(rèn)值)
避免使用同步請求:因?yàn)槲覀儫o法設(shè)置請求超時(shí)時(shí)間(xhr.timeout為0,即不限時(shí))。在不限制超時(shí)的情況下,有可能同步請求一直處于pending狀態(tài),服務(wù)端遲遲不返回響應(yīng),這樣整個(gè)頁面就會一直阻塞,無法響應(yīng)用戶的其他交互。
8 如何獲取上傳、下載進(jìn)度
我們可以通過onprogress事件來實(shí)時(shí)顯示進(jìn)度,默認(rèn)情況下這個(gè)事件每50ms觸發(fā)一次。需要注意的是,上傳過程和下載過程觸發(fā)的是不同對象的onprogress事件:
- 上傳觸發(fā)的是xhr.upload對象的 onprogress事件
- 下載觸發(fā)的是xhr對象的onprogress事件
xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;
function updateProgress(event) {
if (event.lengthComputable) {
var completedPercent = event.loaded / event.total;
}
}
xhr相關(guān)事件

每一XMLHttpRequest對象都有一個(gè)upload屬性,而upload是一個(gè)XMLHttpRequestUpload對象.XMLHttpRequest和XMLHttpRequestUpload對象共同擁有上述(除onreadystatechange事件)事件。onreadystatechange是XMLHttpRequest對象獨(dú)有的事件
事件觸發(fā)順序
- 觸發(fā)xhr.onreadystatechange(之后每次readyState變化時(shí),都會觸發(fā)一次)
- 觸發(fā)xhr.onloadstart
上傳階段開始:
- 觸發(fā)xhr.upload.onloadstart
- 觸發(fā)xhr.upload.onprogress
- 觸發(fā)xhr.upload.onload
- 觸發(fā)xhr.upload.onloadend
上傳結(jié)束,下載階段開始:
- 觸發(fā)xhr.onprogress
- 觸發(fā)xhr.onload
- 觸發(fā)xhr.onloadend
發(fā)生abort/timeout/error異常的處理
- 一旦發(fā)生abort或timeout或error異常,先立即中止當(dāng)前請求
- 將 readystate 置為4,并觸發(fā) xhr.onreadystatechange事件
- 如果上傳階段還沒有結(jié)束,則依次觸發(fā)以下事件:
- xhr.upload.onprogress
- xhr.upload.[onabort或ontimeout或onerror]
- xhr.upload.onloadend
- 注意不會觸發(fā)onloadstart和onload事件
- 觸發(fā) xhr.onprogress事件
- 觸發(fā) xhr.[onabort或ontimeout或onerror]事件
- 觸發(fā)xhr.onloadend 事件
- 注意不會觸發(fā)onloadstart和onload事件
- 注意: 這時(shí)候的xhr.readyState為4,xhr.status為0
在哪個(gè)事件中注冊成功回調(diào)
從上面介紹的事件中,可以知道若xhr請求成功,就會觸發(fā)xhr.onreadystatechange和xhr.onload兩個(gè)事件。由于xhr.onreadystatechange是每次xhr.readyState變化時(shí)都會觸發(fā),而不是xhr.readyState=4時(shí)才觸發(fā)(例如發(fā)生abort、timeout、error異常,會先終止當(dāng)前請求,將readyState設(shè)置為4,并觸發(fā)onreadystatechange事件),因此建議在onload事件中注冊成功回調(diào)
xhr.onload = function () {
//如果請求成功
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
//do successCallback
}
}
為什么要對xhr.status進(jìn)行上述判斷
xhr.status代表相應(yīng)的HTTP狀態(tài)
以2開頭的狀態(tài)碼,代表請求已經(jīng)成功被服務(wù)器接收、理解、并接受
狀態(tài)代碼304代表請求的資源并沒有修改,可以直接使用瀏覽器中緩存的版本
其他以3開頭的狀態(tài)代碼則表示需要客戶端采取進(jìn)一步的操作才能完成請求。
status和readyState
- status是響應(yīng)的HTTP狀態(tài),statusText是HTTP狀態(tài)的說明
- readyState是表示在請求/響應(yīng)過程中的當(dāng)前活動處于哪個(gè)階段