详解XMLHttpRequest(一)同步请求和异步请求


Posted in Javascript onSeptember 14, 2016

XMLHttpRequest 让发送一个HTTP请求变得非常容易。你只需要简单的创建一个请求对象实例,打开一个URL,然后发送这个请求。当传输完毕后,结果的HTTP状态以及返回的响应内容也可以从请求对象中获取。 

通过XMLHttpRequest生成的请求可以有两种方式来获取数据,异步模式或同步模式。请求的类型是由这个XMLHttpRequest对象的open()方法的第三个参数async的值决定的。如果该参数的值为false,则该XMLHttpRequest请求以同步模式进行,否则该过程将以异步模式完成。

两种通信模式:同步和异步请求: 

同步请求
 主线程中的同步请求会阻塞页面,由于对用户体验的糟糕效果,部分最新浏览器在主线程上的同步请求已经被弃用。在极少数情况下,使用同步模式的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,所以该请求实际上也是异步的.
 可以使用类似的方法,让脚本在后台与服务器交互,预加载某些内容.查看使用web workers了解更多详情

 2.不得不使用同步请求的情况
 在少数情况下,只能使用同步模式的XMLHttpRequest请求.比如在 window.onunload和window.onbeforeunload 事件处理函数中。在页面unload事件处理函数中使用异步的XMLHttpRequest会引发这样的问题:当响应返回之后,页面已经不复存在,所有变量和回调函数也已经销毁.结果只能引起一个错误 ,“函数未定义”。解决办法是在这里使用同步模式的请求,这样的话,当请求完成之前,页面不会被关闭.

window.onbeforeunload = function () {
 var oReq = new XMLHttpRequest();
 oReq.open("GET", "logout.php?nick=" + escape(myName), false); // 同步请求
 oReq.send(null);
 if (oReq.responseText.trim() !== "已退出"); { // "已退出"是返回的数据
return "退出失败,您想手动执行退出吗?";
 }
};

异步请求
 使用异步模式的话,当数据完全请求回来以后,会执行一个指定的回调函数, 在执行请求的同时,浏览器可以正常的执行其他事务的处理。 

3.例子: 创建一个标准的方法来读取外部文件
 在一些需求情况下,必须读取多个外部文件. 这是一个标准的函数. 该函数使用XMLHttpRequest对象进行异步请求.而且可以为每个文件读取完成后指定不同的回调函数.

function loadFile (sURL, timeout, fCallback /*, 传入参数1, 传入参数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函数的用法:

function showMessage (sMsg) {
 alert(sMsg + this.responseText);
}
loadFile("message.txt", 200, showMessage, "New message!\\n");

第1行定义一个函数,当文件读取完毕后,fCallback函数会以第3个参数以后的所有参数为自己的参数来被调用.
第3行使用一个超时设置,来避免你的代码为了等候读取请求的返回数据长时间执行,通过为XMLHttpRequest对象的timeout 属性赋值来指定
 第6行为onreadystatechange事件句柄指定了回调函数,函数在每次执行时,检查请求是否结束(请求状态为4),如果是的话,判断请求是否成功(HTTP状态吗是否为200),如果是的话,输出页面源码,如果请求出现了错误,输出错误信息.
 第15行指定第三个参数为true,表示该请求应该以异步模式执行.

 4.例子: 使用异步请求,不使用闭包.

function switchXHRState() {
 switch (this.readyState) {
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.onreadystatechange = switchXHRState;
 oReq.open("GET", sURL, true);
 oReq.send(null);
}

使用 bind: 

function switchXHRState(fCallback, aArguments) {
 switch (this.readyState) {
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.onreadystatechange = switchXHRState.bind(oReq, fCallback, Array.prototype.slice.call(arguments, 2));
 oReq.open("GET", sURL, true);
 oReq.send(null);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery ctrl+Enter shift+Enter实现代码
Feb 07 Javascript
jquery.blockUI.js上传滚动等待效果实现思路及代码
Mar 18 Javascript
jquery实现盒子下拉效果示例代码
Sep 12 Javascript
JS 实现BASE64_ENCODE和BASE64_DECODE(实例代码)
Nov 13 Javascript
在javascript中如何得到中英文混合字符串的长度
Jan 17 Javascript
bootstrap中添加额外的图标实例代码
Feb 15 Javascript
mui 打开新窗口的方式总结及注意事项
Aug 20 Javascript
Spring Boot/VUE中路由传递参数的实现代码
Mar 02 Javascript
vue2.0页面前进刷新回退不刷新的实现方法
Jul 31 Javascript
微信小程序云开发详细教程
May 16 Javascript
微信小程序动态添加和删除组件的现实
Feb 28 Javascript
JavaScript 判断数据类型的4种方法
Sep 11 Javascript
AngularJs ng-route路由详解及实例代码
Sep 14 #Javascript
js实现文字截断功能
Sep 14 #Javascript
jQuery版AJAX简易封装代码
Sep 14 #Javascript
原生JS实现首页进度加载动画
Sep 14 #Javascript
jquery判断iPhone、Android设备类型
Sep 14 #Javascript
Angularjs 实现分页功能及示例代码
Sep 14 #Javascript
Angularjs CURD 详解及实例代码
Sep 14 #Javascript
You might like
《雄兵连》《烈阳天道》真的来了
2020/07/13 国漫
PHP中用正则表达式清除字符串的空白
2011/01/17 PHP
PHP基于PDO实现的SQLite操作类【包含增删改查及事务等操作】
2017/06/21 PHP
谷歌浏览器 insertCell与appendChild的区别
2009/02/12 Javascript
经典海量jQuery插件 大家可以收藏一下
2010/02/07 Javascript
javascript异步编程代码书写规范Promise学习笔记
2015/02/11 Javascript
jQuery实现单击弹出Div层窗口效果(可关闭可拖动)
2015/09/19 Javascript
Javascript函数式编程简单介绍
2015/10/11 Javascript
AngularJS入门教程之迭代器过滤详解
2016/08/18 Javascript
通过扫描二维码打开app的实现代码
2016/11/10 Javascript
jQuery简单自定义图片轮播插件及用法示例
2016/11/21 Javascript
JS冒泡事件与事件捕获实例详解
2016/11/25 Javascript
JSON 数据详解及实例代码分析
2017/01/20 Javascript
利用Node.js+Koa框架实现前后端交互的方法
2017/02/27 Javascript
nodejs中模块定义实例详解
2017/03/18 NodeJs
基于Bootstrap表单验证功能
2017/11/17 Javascript
vue+element项目中过滤输入框特殊字符小结
2019/08/07 Javascript
基于JavaScript实现随机点名器
2021/02/25 Javascript
编写Python脚本使得web页面上的代码高亮显示
2015/04/24 Python
python计算方程式根的方法
2015/05/07 Python
详解Python命令行解析工具Argparse
2016/04/20 Python
Python正确重载运算符的方法示例详解
2017/08/27 Python
python 删除列表里所有空格项的方法总结
2018/04/18 Python
python3.7 使用pymssql往sqlserver插入数据的方法
2019/07/08 Python
Python 处理文件的几种方式
2019/08/23 Python
Pandas 解决dataframe的一列进行向下顺移问题
2019/12/27 Python
Python的赋值、深拷贝与浅拷贝的区别详解
2020/02/12 Python
Vero Moda西班牙官方购物网站:丹麦BESTSELLER旗下知名女装品牌
2018/04/27 全球购物
市委常委班子党的群众路线教育实践活动整改措施
2014/10/02 职场文书
高端收音机+蓝牙音箱,JBL TUNER FM带收音蓝牙音箱评测
2021/04/24 无线电
python3实现常见的排序算法(示例代码)
2021/07/04 Python
Django模型层实现多表关系创建和多表操作
2021/07/21 Python
详解JS数组方法
2021/11/20 Javascript
win11无线投屏在哪设置? win11无线投屏功能的使用方法
2022/04/08 数码科技
SpringBoot详解整合Redis缓存方法
2022/07/15 Java/Android
HTML页面点击按钮关闭页面的多种方式
2022/12/24 HTML / CSS