如果請求過了很久還沒有成功,為了不會(huì)白白占用的網(wǎng)絡(luò)資源,我們一般會(huì)主動(dòng)終止請求。XMLHttpRequest提供了timeout屬性來允許設(shè)置請求的超時(shí)時(shí)間。
xhr.timeout
單位:milliseconds 毫秒
默認(rèn)值:0,即不設(shè)置超時(shí)
很多同學(xué)都知道:從請求開始算起,若超過 timeout 時(shí)間請求還沒有結(jié)束(包括成功/失敗),則會(huì)觸發(fā)ontimeout事件,主動(dòng)結(jié)束該請求。
【那么到底什么時(shí)候才算是請求開始?】
——xhr.onloadstart事件觸發(fā)的時(shí)候,也就是你調(diào)用xhr.send()方法的時(shí)候。
因?yàn)閤hr.open()只是創(chuàng)建了一個(gè)連接,但并沒有真正開始數(shù)據(jù)的傳輸,而xhr.send()才是真正開始了數(shù)據(jù)的傳輸過程。只有調(diào)用了xhr.send(),才會(huì)觸發(fā)xhr.onloadstart 。
【那么什么時(shí)候才算是請求結(jié)束?】
—— xhr.loadend事件觸發(fā)的時(shí)候。
另外,還有2個(gè)需要注意的坑兒:
可以在 send()之后再設(shè)置此xhr.timeout,但計(jì)時(shí)起始點(diǎn)仍為調(diào)用xhr.send()方法的時(shí)刻。
當(dāng)xhr為一個(gè)sync同步請求時(shí),xhr.timeout必須置為0,否則會(huì)拋錯(cuò)。原因可以參考本文的【如何發(fā)一個(gè)同步請求】一節(jié)。
如何發(fā)一個(gè)同步請求
xhr默認(rèn)發(fā)的是異步請求,但也支持發(fā)同步請求(當(dāng)然實(shí)際開發(fā)中應(yīng)該盡量避免使用)。到底是異步還是同步請求,由xhr.open()傳入的async參數(shù)決定。
open(method, url [, async = true [, username = null [, password = null]]])
method: 請求的方式,如GET/POST/HEADER等,這個(gè)參數(shù)不區(qū)分大小寫
url: 請求的地址,可以是相對地址如example.php,這個(gè)相對是相對于當(dāng)前網(wǎng)頁的url路徑;也可以是絕對地址如
async: 默認(rèn)值為true,即為異步請求,若async=false,則為同步請求
在我認(rèn)真研讀W3C 的 xhr 標(biāo)準(zhǔn)前,我總以為同步請求和異步請求只是阻塞和非阻塞的區(qū)別,其他什么事件觸發(fā)、參數(shù)設(shè)置應(yīng)該是一樣的,事實(shí)證明我錯(cuò)了。
W3C 的 xhr標(biāo)準(zhǔn)中關(guān)于open()方法有這樣一段說明:
Throws an “InvalidAccessError” exception if async is false, the JavaScript global environment is a document environment, and either the timeout attribute is not zero, the withCredentials attribute is true, or the responseType attribute is not the empty string.
從上面一段說明可以知道,當(dāng)xhr為同步請求時(shí),有如下限制:
xhr.timeout必須為0
xhr.withCredentials必須為 false
xhr.responseType必須為""(注意置為"text"也不允許)
若上面任何一個(gè)限制不滿足,都會(huì)拋錯(cuò),而對于異步請求,則沒有這些參數(shù)設(shè)置上的限制。
之前說過頁面中應(yīng)該盡量避免使用sync同步請求,為什么呢?
因?yàn)槲覀儫o法設(shè)置請求超時(shí)時(shí)間(xhr.timeout為0,即不限時(shí))。在不限制超時(shí)的情況下,有可能同步請求一直處于pending狀態(tài),服務(wù)端遲遲不返回響應(yīng),這樣整個(gè)頁面就會(huì)一直阻塞,無法響應(yīng)用戶的其他交互。
另外,標(biāo)準(zhǔn)中并沒有提及同步請求時(shí)事件觸發(fā)的限制,但實(shí)際開發(fā)中我確實(shí)遇到過部分應(yīng)該觸發(fā)的事件并沒有觸發(fā)的現(xiàn)象。如在 chrome中,當(dāng)xhr為同步請求時(shí),在xhr.readyState由2變成3時(shí),并不會(huì)觸發(fā) onreadystatechange事件,xhr.upload.onprogress和 xhr.onprogress事件也不會(huì)觸發(fā)。
如何獲取上傳、下載的進(jìn)度
在上傳或者下載比較大的文件時(shí),實(shí)時(shí)顯示當(dāng)前的上傳、下載進(jìn)度是很普遍的產(chǎ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) {varcompletedPercent =event.loaded /event.total; } } 可以發(fā)送什么類型的數(shù)據(jù)
void send(data);
xhr.send(data)的參數(shù)data可以是以下幾種類型:
ArrayBuffer
Blob
Document
DOMString
FormData
如果是 GET/HEAD請求,send()方法一般不傳參或傳 。不過即使你真?zhèn)魅肓藚?shù),參數(shù)也最終被忽略,xhr.send(data)中的data會(huì)被置為 .
xhr.send(data)中data參數(shù)的數(shù)據(jù)類型會(huì)影響請求頭部content-type的默認(rèn)值:
如果data是 Document 類型,同時(shí)也是HTML Document類型,則content-type默認(rèn)值為text/html;charset=UTF-8;否則為application/xml;charset=UTF-8;
如果data是 DOMString 類型,content-type默認(rèn)值為text/plain;charset=UTF-8;
如果data是 FormData 類型,content-type默認(rèn)值為multipart/form-data; boundary=[xxx]
如果data是其他類型,則不會(huì)設(shè)置content-type的默認(rèn)值
當(dāng)然這些只是content-type的默認(rèn)值,但如果用xhr.setRequestHeader()手動(dòng)設(shè)置了中content-type的值,以上默認(rèn)值就會(huì)被覆蓋。
電子發(fā)燒友App















評論