详解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 相关文章推荐
Add a Table to a Word Document
Jun 15 Javascript
javascript强大的日期函数代码分享
Sep 04 Javascript
javascript获取web应用根目录的方法
Feb 12 Javascript
浅谈JS闭包中的循环绑定处理程序
Nov 09 Javascript
简单介绍JavaScript中字符串创建的基本方法
Jul 07 Javascript
Bootstrap每天必学之导航条(二)
Mar 01 Javascript
Jquery Easyui验证组件ValidateBox使用详解(20)
Dec 18 Javascript
vue滚动轴插件better-scroll使用详解
Oct 17 Javascript
vue单页面打包文件大?首次加载慢?nginx带你飞,从7.5M到1.3M蜕变过程(推荐)
Jan 16 Javascript
vue弹窗消息组件的使用方法
Sep 24 Javascript
vue实现简单loading进度条
Jun 06 Javascript
node.js express捕获全局异常的三种方法实例分析
Dec 27 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
一个目录遍历函数
2006/10/09 PHP
php批量删除数据
2007/01/18 PHP
用js进行url编码后用php反解以及用php实现js的escape功能函数总结
2010/02/08 PHP
使用Appcan客户端自动更新PHP版本号(全)
2015/07/31 PHP
Nigma vs Alliance BO5 第四场2.14
2021/03/10 DOTA
JavaScript 参考教程
2006/12/29 Javascript
js操作textarea方法集合封装(兼容IE,firefox)
2011/02/22 Javascript
Textbox控件注册回车事件及触发按钮提交事件具体实现
2013/03/04 Javascript
用原生JS获取CLASS对象(很简单实用)
2014/10/15 Javascript
js+html5通过canvas指定开始和结束点绘制线条的方法
2015/06/05 Javascript
jQuery easyui刷新当前tabs的方法
2016/09/23 Javascript
jQuery使用zTree插件实现可拖拽的树示例
2017/09/23 jQuery
原生JS实现图片无缝滚动方法(附带封装的运动框架)
2017/10/01 Javascript
webpack 3.X学习之多页面打包的方法
2018/09/04 Javascript
微信小程序实现列表页的点赞和取消点赞功能
2018/11/02 Javascript
Node.js实现简单管理系统
2019/09/23 Javascript
vue实现配置全局访问路径头(axios)
2019/11/01 Javascript
element中Steps步骤条和Tabs标签页关联的解决
2020/12/08 Javascript
Python学习资料
2007/02/08 Python
简单介绍Python的Django框架的dj-scaffold项目
2015/05/30 Python
Django配置celery(非djcelery)执行异步任务和定时任务
2018/07/16 Python
python根据list重命名文件夹里的所有文件实例
2018/10/25 Python
python中正则表达式与模式匹配
2019/05/07 Python
python+openCV调用摄像头拍摄和处理图片的实现
2019/08/06 Python
python3使用Pillow、tesseract-ocr与pytesseract模块的图片识别的方法
2020/02/26 Python
python用Tkinter做自己的中文代码编辑器
2020/09/07 Python
css3实例教程 一款纯css3实现的发光屏幕旋转特效
2014/12/07 HTML / CSS
科颜氏法国官网:Kiehl’s法国
2019/08/20 全球购物
电子商务个人职业生涯规划范文
2014/02/12 职场文书
实习推荐信
2014/05/10 职场文书
工程技术负责人岗位职责
2015/04/13 职场文书
“学党章、守党纪、讲党规”学习心得体会
2016/01/14 职场文书
党员理论学习心得体会
2016/01/21 职场文书
Redis读写分离搭建的完整步骤
2021/09/14 Redis
Python爬虫网络请求之代理服务器和动态Cookies
2022/04/12 Python
《游戏王:大师决斗》新活动上线 若无符合卡组可免费租用
2022/04/13 其他游戏