詳解XMLHttpRequest(一)同步請求和異步請求
XMLHttpRequest 讓發(fā)送一個HTTP請求變得非常容易。你只需要簡單的創(chuàng)建一個請求對象實例,打開一個URL,然后發(fā)送這個請求。當傳輸完畢后,結(jié)果的HTTP狀態(tài)以及返回的響應內(nèi)容也可以從請求對象中獲取。
通過XMLHttpRequest生成的請求可以有兩種方式來獲取數(shù)據(jù),異步模式或同步模式。請求的類型是由這個XMLHttpRequest對象的open()方法的第三個參數(shù)async的值決定的。如果該參數(shù)的值為false,則該XMLHttpRequest請求以同步模式進行,否則該過程將以異步模式完成。
兩種通信模式:同步和異步請求:
同步請求
主線程中的同步請求會阻塞頁面,由于對用戶體驗的糟糕效果,部分最新瀏覽器在主線程上的同步請求已經(jīng)被棄用。在極少數(shù)情況下,使用同步模式的XMLHttpRequests會比使用異步模式更適合。
1.在Worker中使用XMLHttpRequest時,同步請求比異步請求更適合。
主頁中代碼:
<script type="text/javascript">
var oMyWorker = new Worker("myTask.js");
oMyWorker.onmessage = function(oEvent) {
alert("Worker said: " + oEvent.data);
};
oMyWorker.postMessage("Hello");
</script>
myFile.txt ( XMLHttpRequest對象同步請求的文件):
Hello World!!
包含了Worker代碼:myTask.js
self.onmessage = function (oEvent) {
if (oEvent.data === "Hello") {
var oReq = new XMLHttpRequest();
oReq.open("GET", "myFile.txt", false); // 同步請求
oReq.send(null);
self.postMessage(oReq.responseText);
}
};
注意: 由于使用了Worker,所以該請求實際上也是異步的.
可以使用類似的方法,讓腳本在后臺與服務器交互,預加載某些內(nèi)容.查看使用web workers了解更多詳情
2.不得不使用同步請求的情況
在少數(shù)情況下,只能使用同步模式的XMLHttpRequest請求.比如在 window.onunload和window.onbeforeunload 事件處理函數(shù)中。在頁面unload事件處理函數(shù)中使用異步的XMLHttpRequest會引發(fā)這樣的問題:當響應返回之后,頁面已經(jīng)不復存在,所有變量和回調(diào)函數(shù)也已經(jīng)銷毀.結(jié)果只能引起一個錯誤 ,“函數(shù)未定義”。解決辦法是在這里使用同步模式的請求,這樣的話,當請求完成之前,頁面不會被關閉.
window.onbeforeunload = function () {
var oReq = new XMLHttpRequest();
oReq.open("GET", "logout.php?nick=" + escape(myName), false); // 同步請求
oReq.send(null);
if (oReq.responseText.trim() !== "已退出"); { // "已退出"是返回的數(shù)據(jù)
return "退出失敗,您想手動執(zhí)行退出嗎?";
}
};
異步請求
使用異步模式的話,當數(shù)據(jù)完全請求回來以后,會執(zhí)行一個指定的回調(diào)函數(shù), 在執(zhí)行請求的同時,瀏覽器可以正常的執(zhí)行其他事務的處理。
3.例子: 創(chuàng)建一個標準的方法來讀取外部文件
在一些需求情況下,必須讀取多個外部文件. 這是一個標準的函數(shù). 該函數(shù)使用XMLHttpRequest對象進行異步請求.而且可以為每個文件讀取完成后指定不同的回調(diào)函數(shù).
function loadFile (sURL, timeout, fCallback /*, 傳入?yún)?shù)1, 傳入?yún)?shù)2, 等 */) {
var aPassArgs = Array.prototype.slice.call(arguments, 3), oReq = new XMLHttpRequest();
oReq.ontimeout = function() {
console.log("請求超時.");
}
oReq.onreadystatechange = function() {
if (oReq.readyState === 4) {
if (oReq.status === 200) {
fCallback.apply(oReq, aPassArgs);
} else {
console.log("Error", oReq.statusText);
}
}
};
oReq.open("GET", sURL, true);
oReq.timeout = timeout;
oReq.send(null);
}
loadFile函數(shù)的用法:
function showMessage (sMsg) {
alert(sMsg + this.responseText);
}
loadFile("message.txt", 200, showMessage, "New message!\\n");
第1行定義一個函數(shù),當文件讀取完畢后,fCallback函數(shù)會以第3個參數(shù)以后的所有參數(shù)為自己的參數(shù)來被調(diào)用.
第3行使用一個超時設置,來避免你的代碼為了等候讀取請求的返回數(shù)據(jù)長時間執(zhí)行,通過為XMLHttpRequest對象的timeout 屬性賦值來指定
第6行為onreadystatechange事件句柄指定了回調(diào)函數(shù),函數(shù)在每次執(zhí)行時,檢查請求是否結(jié)束(請求狀態(tài)為4),如果是的話,判斷請求是否成功(HTTP狀態(tài)嗎是否為200),如果是的話,輸出頁面源碼,如果請求出現(xiàn)了錯誤,輸出錯誤信息.
第15行指定第三個參數(shù)為true,表示該請求應該以異步模式執(zhí)行.
4.例子: 使用異步請求,不使用閉包.
function switchXHRState() {
switch (this.readyState) {
case 0: console.log("還沒調(diào)用open()方法."); break;
case 1: console.log("還沒調(diào)用send()方法."); break;
case 2: console.log("已經(jīng)調(diào)用send()方法,響應頭和響應狀態(tài)已經(jīng)返回."); break;
case 3: console.log("下載中,已經(jīng)得到部分響應實體."); break;
case 4: console.log("請求完成!"); this.callback.apply(this, this.arguments);
}
};
function loadFile (sURL, fCallback /*, 傳入?yún)?shù)1, 傳入?yún)?shù)2, 等 */) {
var oReq = new XMLHttpRequest();
oReq.callback = fCallback;
oReq.arguments = Array.prototype.slice.call(arguments, 2);
oReq.onreadystatechange = switchXHRState;
oReq.open("GET", sURL, true);
oReq.send(null);
}
使用 bind:
function switchXHRState(fCallback, aArguments) {
switch (this.readyState) {
case 0: console.log("還沒調(diào)用open()方法."); break;
case 1: console.log("還沒調(diào)用send()方法."); break;
case 2: console.log("已經(jīng)調(diào)用send()方法,響應頭和響應狀態(tài)已經(jīng)返回."); break;
case 3: console.log("下載中,已經(jīng)得到部分響應實體."); break;
case 4: console.log("請求完成!"); fCallback.apply(this, aArguments);
}
};
function loadFile (sURL, fCallback /*, 傳入?yún)?shù)1, 傳入?yún)?shù)2, 等 */) {
var oReq = new XMLHttpRequest();
oReq.onreadystatechange = switchXHRState.bind(oReq, fCallback, Array.prototype.slice.call(arguments, 2));
oReq.open("GET", sURL, true);
oReq.send(null);
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
js實現(xiàn)將選中內(nèi)容分享到新浪或騰訊微博
這篇文章主要介紹了js實現(xiàn)將選中內(nèi)容分享到新浪或騰訊微博,需要的朋友可以參考下2015-12-12
javascript中的self和this用法小結(jié)
本篇文章主要是對javascript中的self和this用法進行了詳細的總結(jié)介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-02-02
javascript委托(Delegate)blur和focus用法實例分析
這篇文章主要介紹了javascript委托(Delegate)blur和focus用法,實例分析了javascript委托的用法及針對常見瀏覽器的使用技巧,需要的朋友可以參考下2015-05-05
JavaScript中改變this指向的三種方式總結(jié)
this?指向的值是可以通過手動方式去改變的,比如call、bind、apply方法,本文主要為大家介紹了這三種方式的具體實現(xiàn)步驟,需要的可以參考下2023-12-12

