XHR对象send方法的同异步问题

理解XHR对象send方法的异步特性及其影响

  XHR对象上的send方法不仅是用于发送数据部分,只有调用了send方法,整个HTTP请求头才会被发出,然后才是真正的内容部分。如此复杂的过程在规范中也没有具体的定义,所以目前各大浏览器上的实现都存在细微的差异,特别是同异步这个大坑再次中枪。

一个精密的实验

  其实我以前一直以为send方法总是同步发起的(注意这里讨论的是“发起”这个行为本身的同异步,open方法的第三个参数始终为true,不讨论false的情况),还在讨论同异步的文章中使用了XHR对象的例子,现在看来确实是个不恰当的例子。在一些浏览器中XHR对象的send方法确实是同步发起的,但并不是所有浏览器都这样,可以通过下面的实验来证实(NodeJS 的部分需要 harmony 和 use_strict):
//nodejsrequire('http').createServer(function(request,response){ response.setHeader('Content-Type','text/html'); if(request.url=='/test'){ console.log(request.url); let connection=request.connection; connection.write('HTTP/1.1 100 Continue\n\n'); console.log(100); request.on('data',function(e){ console.log(e+""); response.end('ok'); }); }else{ let path=process.cwd()+request.url; require('fs').readFile(path,function(error,data){ response.end(error?'error':data); }); };}).listen(1234);<!--test.html-->
<script>
var xhr=new XMLHttpRequest;
xhr.onreadystatechange=function(){
console.log(xhr.readyState,xhr.status);
};
xhr.open("POST","test");
xhr.send("data");
var t=new Date;
while(new Date-t<3000);
</script>
  这个测试在三大主流浏览器上测试会得到三个不同的结果:
  • Chrome39:请求同步发出,死循环不会影响请求
  • Firefox33:请求被注册到下一个消息中异步发出
  • IE11:请求的头部分同步发出,内容部分被注册到下一个消息中异步发出

实验结果影响的现实

  这个结果对实际运用有什么影响呢?在同步过程中多次调用open方法就能看出差异。XHR对象在调用open方法时会停止原来的工作,于是有以下几种情况:
  • Chrome的send是同步发出的,即使在send之后马上调用open也无法停止已经send的东西了,已经泼出去的水,根本停不下来。
  • Firefox就完全不同,由于是注册到下一个消息中,send后马上调用open就会取消掉原先注册但还没执行到的动作。
  • IE比较奇葩,在调动send时头已经发出了,这部分是收不回来的。send后马上调用open只能阻止内容部分的发出。


源引:https://www.web-tinker.com/article/20790.html

<think>我们被要求回答XHR请求是异步还是步的问题。根据引用[1],XHR请求过程包括发送请求、接收响应和处理响应三个步骤。引用[2]提到XHR是传统异步请求方案,但引用[4]中展示了XHR既可以步也可以异步执行。因此,我们需要明确指出XHR支持两种模式。 回答结构: 1. 明确回答:XHR既可以是异步的,也可以是步的。 2. 解释两种模式的区别:异步(默认)不会阻塞代码执行,而步会阻塞。 3. 说明如何设置:通过`open`方法的第三个参数(true为异步,false为步)。 4. 对比两种模式的优缺点和应用场景:异步是推荐的主流方式,步在特殊情况下使用(如Web Worker)。 5. 给出代码示例:分别展示异步步请求的代码片段。 6. 注意事项:步请求在UI线程中使用会导致页面冻结,应避免。 7. 生成相关问题。 引用文献: - 引用[1]说明XHR的过程,我们可以用来解释请求的基本流程。 - 引用[2]提到XHR异步请求方案,但实际它支持步和异步,需要澄清。 - 引用[4]中有关于异步代码的例子,包括setTimeout和事件监听,我们可以用来对比异步行为。 注意:引用标识要自然地添加在相关段落末尾。 生成相关问题:围绕XHR异步使用场景、如何避免阻塞、与Fetch API在异步处理上的区别等。 </think>### XHR 请求的步与异步模式详解 XHR 请求既可以是**异步的**(默认),也可以是**步的**,具体取决于 `open()` 方法的第三个参数设置: #### 1. **异步模式(默认)** - **特性**: - `open("GET", url, true)` 第三个参数为 `true` 时启用 - 请求在后台执行,**不阻塞** JavaScript 主线程 - 通过事件回调(如 `onreadystatechange`) 处理响应 - **优势**: - 页面交互保持流畅,用户体验更好 - 支持超时控制和进度监控(`xhr.timeout`, `xhr.onprogress`) - **代码示例**: ```javascript const xhr = new XMLHttpRequest(); xhr.open("GET", "https://api.example.com/data", true); // 异步模式 xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { console.log("异步响应:", xhr.responseText); } }; xhr.send(); console.log("请求已发送,继续执行其他代码"); // 立即执行 ``` #### 2. **步模式** - **特性**: - `open("GET", url, false)` 第三个参数为 `false` 时启用 - 请求**阻塞** JavaScript 主线程直到响应完成 - 直接通过 `send()` 后的代码处理响应 - **风险**: - 导致页面冻结,用户无法操作界面 - 现代浏览器已限制在主线程中使用(仅允许 Web Worker) - **代码示例**: ```javascript const xhr = new XMLHttpRequest(); xhr.open("GET", "https://api.example.com/data", false); // 步模式 xhr.send(); // 此处阻塞直到响应完成 if (xhr.status === 200) { console.log("步响应:", xhr.responseText); } console.log("必须等待请求完成才能执行"); // 阻塞后执行 ``` #### 3. 关键区别对比 | 特性 | 异步模式 | 步模式 | |---------------------|------------------------------|------------------------------| | **`open()` 参数** | `true`(默认) | `false` | | **线程阻塞** | 否 | 是 | | **回调机制** | 事件监听 (`onreadystatechange`) | 阻塞等待响应 | | **超时控制** | 支持 (`xhr.timeout`) | 不支持 | | **浏览器兼容性** | 所有浏览器 | 主线程中已弃用(除 Worker)[^4] | | **用户体验** | 流畅 | 页面卡顿 | #### 4. 为什么异步是推荐方案? 1. **遵循 JavaScript 事件循环机制** 异步调用将请求交给浏览器网络线程处理,主线程继续执行其他任务(如渲染 UI、响应用户点击)[^3]。 2. **避免性能灾难** 步请求阻塞期间,浏览器会显示“无响应”警告。实验证明步请求超过 500ms 会导致明显的页面卡顿。 3. **现代开发标准** Fetch API 等新技术**仅支持异步**,步模式已被逐步淘汰[^2]。 >[!WARNING] >在主线程中使用XHR 会导致: >- 浏览器控制台警告:`Synchronous XMLHttpRequest... is deprecated` >- 部分浏览器(如 Chrome)直接阻断请求 >- React/Vue 等框架中可能引发渲染异常 #### 5. 何时考虑步模式? 仅在特殊场景下使用: - **Web Worker 线程**:后台线程中处理耗时请求 - **页面卸载前**:`beforeunload` 事件中强制发送日志 ```javascript window.addEventListener("beforeunload", () => { const xhr = new XMLHttpRequest(); xhr.open("POST", "/log", false); // 步发送 xhr.send(analyticsData); }); ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值