详细解读XMLHttpRequest(⼀)同步请求和异步请求
本⽂主要参考:
XMLHttpRequest 让发送⼀个HTTP请求变得⾮常容易。你只需要简单的创建⼀个请求对象实例,打开⼀个URL,然后发送这个请求。当传输完毕后,结果的HTTP状态以及返回的响应内容也可以从请求对象中获取。
通过XMLHttpRequest⽣成的请求可以有两种⽅式来获取数据,异步模式或同步模式。请求的类型是由这个XMLHttpRequest对象的open()⽅法的第三个参数async的值决定的。如果该参数的值为false,则该XMLHttpRequest请求以同步模式进⾏,否则该过程将以异步模式完成。
两种通信模式:同步和异步请求:
同步请求
主线程中的同步请求会阻塞页⾯,由于对⽤户体验的糟糕效果,部分最新浏览器在主线程上的同步请求已经被弃⽤。在极少数情况下,使⽤同步模式的XMLHttpRequests会⽐使⽤异步模式更适合。
1. 在Worker中使⽤XMLHttpRequest时,同步请求⽐异步请求更适合。
主页中代码:
<script type="text/javascript">
var oMyWorker = new Worker("myTask.js");
alert("Worker said: " + oEvent.data);
};
oMyWorker.postMessage("Hello");
</script>
< ( XMLHttpRequest对象同步请求的⽂件):
Hello World!!
包含了Worker代码:myTask.js
if (oEvent.data === "Hello") {
var oReq = new XMLHttpRequest();
oReq.open("GET", "", false);  // 同步请求
oReq.send(null);
self.sponseText);
}
函数prototype};
注意: 由于使⽤了Worker,所以该请求实际上也是异步的.
可以使⽤类似的⽅法,让脚本在后台与服务器交互,预加载某些内容.查看使⽤web workers了解更多详情
2. 不得不使⽤同步请求的情况
在少数情况下,只能使⽤同步模式的XMLHttpRequest请求.⽐如在 unload和beforeunload 事件处理函数中。在页⾯unload事件处理函数中使⽤异步的XMLHttpRequest会引发这样的问题:当响应返回之后,页⾯已经不复存在,所有变量和回调函数也已经销毁.结果只能引起⼀个错误 ,“函数未定义”。解决办法是在这⾥使⽤同步模式的请求,这样的话,当请求完成之前,页⾯不会被关闭.
var oReq = new XMLHttpRequest();
oReq.open("GET", "logout.php?nick=" + escape(myName), false);  // 同步请求
oReq.send(null);
if (im() !== "已退出"); {  // "已退出"是返回的数据
return "退出失败,您想⼿动执⾏退出吗?";
}
};
异步请求
使⽤异步模式的话,当数据完全请求回来以后,会执⾏⼀个指定的回调函数, 在执⾏请求的同时,浏览器可以正常的执⾏其他事务的处理。
1. 例⼦: 创建⼀个标准的⽅法来读取外部⽂件
在⼀些需求情况下,必须读取多个外部⽂件. 这是⼀个标准的函数. 该函数使⽤XMLHttpRequest对象进⾏异步请求.⽽且可以为每个⽂件读取完成后指定不同的回调函数.
function loadFile (sURL, timeout, fCallback /*, 传⼊参数1, 传⼊参数2, 等 */) {
var aPassArgs = Array.prototype.slice.call(arguments, 3), oReq = new XMLHttpRequest();
console.log("请求超时.");
}
if (adyState === 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函数的⽤法:
function showMessage (sMsg) {
alert(sMsg + sponseText);
}
loadFile("", 200, showMessage, "New message!\\n");
第1⾏定义⼀个函数,当⽂件读取完毕后,fCallback函数会以第3个参数以后的所有参数为⾃⼰的参数来被调⽤.
第3⾏使⽤⼀个超时设置,来避免你的代码为了等候读取请求的返回数据长时间执⾏,通过为XMLHttpRequest对象的timeout 属性赋值来指定第6⾏为onreadystatechange事件句柄指定了回调函数,函数在每次执⾏时,检查请求是否结束(请求状态为4),如果是的话,判断请求是否成功(HTTP状态吗是否为200),如果是的话,输出页⾯源码,如果请求出现了错误,输出错误信息.
第15⾏指定第三个参数为true,表⽰该请求应该以异步模式执⾏.
2. 例⼦: 使⽤异步请求,不使⽤闭包.
function switchXHRState() {
switch (adyState) {
case 0: console.log("还没调⽤open()⽅法."); break;
case 1: console.log("还没调⽤send()⽅法."); break;
case 2: console.log("已经调⽤send()⽅法,响应头和响应状态已经返回."); break;
case 3: console.log("下载中,已经得到部分响应实体."); break;
case 4: console.log("请求完成!"); this.callback.apply(this, this.arguments);
}
};
function loadFile (sURL, fCallback /*, 传⼊参数1, 传⼊参数2, 等 */) {
var oReq = new XMLHttpRequest();
oReq.callback = fCallback;
oReq.arguments = Array.prototype.slice.call(arguments, 2);
oReq.open("GET", sURL, true);
oReq.send(null);
}
使⽤ bind:
function switchXHRState(fCallback, aArguments) {
switch (adyState) {
case 0: console.log("还没调⽤open()⽅法."); break;
case 1: console.log("还没调⽤send()⽅法."); break;
case 2: console.log("已经调⽤send()⽅法,响应头和响应状态已经返回."); break;
case 3: console.log("下载中,已经得到部分响应实体."); break;
case 4: console.log("请求完成!"); fCallback.apply(this, aArguments);
}
};
function loadFile (sURL, fCallback /*, 传⼊参数1, 传⼊参数2, 等 */) {
var oReq = new XMLHttpRequest();
oReq.open("GET", sURL, true);
oReq.send(null);
}