文章目录
- [1. XMLHttpRequest Level 1](#1. XMLHttpRequest Level 1)
-
-
- [1. 背景和概述](#1. 背景和概述)
- [2. 主要特性与限制](#2. 主要特性与限制)
- [3. 浏览器支持性](#3. 浏览器支持性)
-
- [2. XMLHttpRequest Level 2](#2. XMLHttpRequest Level 2)
-
- [1. 基本内容](#1. 基本内容)
-
- [1. 背景与发展](#1. 背景与发展)
- [2. 新特性与功能](#2. 新特性与功能)
- [3. 浏览器支持性](#3. 浏览器支持性)
- [2. FormData类型](#2. FormData类型)
-
- [1. 定义](#1. 定义)
- [2. 用途](#2. 用途)
-
- [1. 异步表单提交](#1. 异步表单提交)
- [2. 文件上传](#2. 文件上传)
- [3. 构建自定义表单数据](#3. 构建自定义表单数据)
- [3. 用法](#3. 用法)
-
- [1. 从零开始创建FormData对象](#1. 从零开始创建FormData对象)
- [2. 通过HTML表单创建FormData对象](#2. 通过HTML表单创建FormData对象)
- [3. 使用FormData对象上传文件](#3. 使用FormData对象上传文件)
- [4. 常用方法](#4. 常用方法)
- [3. 设置http请求的时限Timeout](#3. 设置http请求的时限Timeout)
-
- [1. 基本用法](#1. 基本用法)
- [2. 属性值规则](#2. 属性值规则)
- [3. 注意事项](#3. 注意事项)
- [4. 浏览器兼容性](#4. 浏览器兼容性)
- [4. overrideMimeType()方法](#4. overrideMimeType()方法)
-
- [1. 背景与目的](#1. 背景与目的)
- [2. 基本用法](#2. 基本用法)
- [3. 功能与作用](#3. 功能与作用)
- [4. 注意事项](#4. 注意事项)
- [5. 与responseType属性的关系](#5. 与responseType属性的关系)
- [5 . 进度事件](#5 . 进度事件)
-
- [1. load事件](#1. load事件)
-
- 1.`load`事件的基本特性
- [2. `load`事件的使用方法](#2.
load
事件的使用方法) - [3. 与其他事件比较](#3. 与其他事件比较)
- [4. `load`事件处理函数中的常见操作](#4.
load
事件处理函数中的常见操作) - [5. 注意事项](#5. 注意事项)
- [2. progress事件](#2. progress事件)
-
- [1. progress事件的基本特性](#1. progress事件的基本特性)
- [2. `progress`事件的属性](#2.
progress
事件的属性) - [3. `progress`事件的使用方法](#3.
progress
事件的使用方法) - [4. `progress`事件与其他事件的比较](#4.
progress
事件与其他事件的比较) - [5. 注意事项](#5. 注意事项)
- [6. 跨域资源共享(CORS)](#6. 跨域资源共享(CORS))
前言
本文主要讲述了XMLHttpRequest Level 1的基本信息和XMLHttpRequest Level 2的详细信息XMLHttpRequest Level 2(XHR Level 2)是XHR Level 1的增强版,它引入了一系列新特性和功能,以改善Web开发中异步请求的处理。
1. XMLHttpRequest Level 1
这里XHR Level 1主要和XHR Level 2放在一起,其中没有什么示例,最好和我发布的另一篇文章js网络请求与远程资源之ajax(二)一起看,那篇文章中有足够的案例。
XMLHttpRequest Level 1(XHR Level 1)是XMLHttpRequest对象的一个早期版本,它为浏览器提供了一种在客户端和服务器之间传输数据的脚本化客户端功能。
1. 背景和概述
XMLHttpRequest(XHR)最初是由微软在Internet Explorer 5中引入的一个ActiveX对象,用于从Web服务器请求数据。随后,Mozilla、Apple、Google等浏览器厂商也实现了类似的功能,最终W3C(万维网联盟)对其进行了标准化,并发布XMLHttpRequest Level 1规范。
2. 主要特性与限制
- 文本数据传输: XMLHttpRequest Level 1主要支持文本数据的传输,无法直接用于读取和上传二进制文件(如图片、视频、音频等)。
- 同步与异步请求: 它支持同步和异步请求,但通常推荐使用异步请求以避免阻塞浏览器的UI线程。
- 同源策略: 受到同源策略的限制,XMLHttpRequest Level 1不能发送跨域请求。这意味着它只能向与当前页面同源的服务器请求数据。
- 缺乏进度信息: 在发送和接收数据的过程中,XMLHttpRequest Level 1无法提供实时的进度信息,只能判断请求是否完成。
- 请求与响应头: 允许开发者设置和获取HTTP请求和响应头,以便进行更细粒度的控制。
3. 浏览器支持性
XMLHttpRequest Level 1得到了所有现代浏览器较好的支持。然而,在一些较旧的浏览器版本中(如IE6、IE7等),可能需要使用特定的方法来创建XMLHttpRequest对象(如使用ActiveXObject)。
2. XMLHttpRequest Level 2
XMLHttpRequest Level 2,是HTML5中引入的一个重要的API更新,它扩展并增强了原有的XHR对象的功能。
1. 基本内容
1. 背景与发展
-
最初由微软在IE 5中引入,用于在客户端与服务器之间异步交换数据。由于其强大的功能,很快被其他浏览器采纳,并成为AJAX技术的核心。
-
随着Web技术的发展,W3C开始考虑标准化XMLHttpRequest接口。2008年2月,W3C提出了XHR Level 2草案,旨在解决旧版XMLHttpRequest的一些限制和不足。
2. 新特性与功能
- 跨域请求(CORS)支持
- XMLHttpRequest Level 2增加了对跨域资源共享(CORS)的支持,允许向不同域名的服务器发出HTTP请求。
- 这使得Web应用能够更方便地与其他域名下的资源进行交互。
- FormData对象管理表单数据
- FormData对象可以模拟表单操作,便于表单数据的序列化和提交。
- 使用FormData对象,可以更方便地处理文件上传和复杂表单数据。
- 文件上传与进度信息
- XMLHttpRequest Level 2支持文件上传,并可以通过监听xhr.upload.onprogress事件获取文件的上传进度。
- 这为用户提供了更好的上传体验,可以实时了解上传进度。
- 设置HTTP请求的时限
- 通过增加timeout属性,可以设置HTTP请求的时限。
- 如果请求在指定时间内未完成,将自动中断请求并触发timeout事件。
- 重写MIME类型
- 通过overrideMimeType()方法,可以重写XHR响应的MIME类型。
- 这在处理服务器返回的响应类型与预期不符时非常有用。
- 二进制数据支持
- XMLHttpRequest Level 2支持获取服务器端的二进制数据。
- 这使得Web应用能够更方便地处理图像、音频等二进制资源。
3. 浏览器支持性
- 并非所有浏览器都实现了XMLHttpRequest Level 2的所有部分,但大多数现代浏览器都支持其部分或全部功能。
- 开发者可以通过检测特定属性或方法的存在性来判断浏览器是否支持某个特定功能。
接下来我们来详细讨论一下XMR Level 2 里的内容
2. FormData类型
1. 定义
FormData是XMLHttpRequest 2级定义的,用于序列化表单数据以及创建与表单格式相同的数据,然后通过XHR(XMLHttpRequest)发送。
2. 用途
FormData对象主要用于以表单的形式收集数据,并通过AJAX或Fetch API异步提交到服务器。它模拟了HTML表单的行为,可以方便地处理表单数据,特别是包含文件上传的情况。以下是FormData对象的主要用处:
1. 异步表单提交
- 避免页面刷新: 通过异步提交表单数据,可以避免页面刷新,提供更好的用户体验。
- 序列化表单数据: 将表单数据序列化成键值对,方便提交到服务器。
2. 文件上传
- 方便处理文件上传:FormData对象可以方便地处理文件上传,无需手动构建复杂的请求体。
- 支持上传进度监控:在上传文件的过程中,可以通过监听相关事件来监控上传进度。
3. 构建自定义表单数据
- 即使没有HTML表单元素:也可以使用FormData创建和提交数据。这对于构建动态表单或处理非表单数据提交的场景非常有用。
3. 用法
1. 从零开始创建FormData对象
js
//创建FormData对象
const fd = new FormData();
//使用append方法添加键值对
fd.append("username","HopeBearer");
fd.append("age",18); // 数字18 会被立即转换为字符串 "18"
//Html 文件类型input,用户选择文件
fd.append("userfile",fileInputElement.files[0]);
//JS file-like对象
let content = `<a id="a"><b id="b">hello!</b></a>`; //新文件的正文
const blob = new Blob([content],{type: "text/xml"});
fd.append("webmasterfile",blob);
const xhr = new XMLHttpRequest();
xhr.open("POST",url);//url为将要访问的链接地址
xhr.send(fd);
备注: 字段"username"和"webmasterfile" 都包含一个文件。字段"age"是数字类型,会被FormData.append()方法转换为字符串(字段类型可以是Blob,File或者字符串: **如果它的字段类型不是Blob也不是File,则会被转换成字符串类)。
上面的实例创建了一个FormData实例,包含"username"、"age"、"userfile" 和 "webmasterfile"四个字段,然后使用 XMLHttpRequest 的 send() 方法发送表单数据。字段 "webmasterfile" 是 Blob 类型。一个 Blob 对象表示一个不可变的,原始数据的类似文件对象。Blob 表示的数据不一定是一个 JavaScript 原生格式。 File 接口基于 Blob,继承 blob 功能并将其扩展为支持用户系统上的文件。你可以通过 Blob() 构造函数创建一个 Blob 对象。
2. 通过HTML表单创建FormData对象
想要构造一个包含 Form 表单数据的 FormData 对象,需要在创建 FormData 对象时指定表单的元素。
备注: FormData将仅使用具有name属性的输入字段。
js
//form表单元素
const formElements = document.querySelector("form");
const xhr = new XMLHttpRequest();
xhr.open("POST",url);//url是将要访问的链接地址
xhr.send(new FormData(formElements));
也可以在创建一个包含Form表单数据的FormData对象之后和发送请求之前,附加额外的数据到FormData对象中,如下:
js
const formElements = document.querySelector("form");
const fd = new FormData(formElements);
const xhr = new XMLHttpRequest();
xhr.open("POST",url);//url是将要访问的链接地址
//添加新的数据
fd.append("otherDataKey","otherDataValue")
xhr.send(fd);
这样就可以在发送请求之前自由地附加不一定是用户编辑的字段到表单数据里。
3. 使用FormData对象上传文件
你还可以使用 FormData 上传文件。使用的时候需要在表单中添加一个文件类型的 input:
html
<form enctype="multipart/form-data" method="post" name="fileinfo">
<label>你的邮箱地址:</label>
<input
type="email"
autocomplete="on"
autofocus
name="userid"
placeholder="email"
required
size="32"
maxlength="64" /><br />
<label>自定义文件标签:</label>
<input type="text" name="filelabel" size="12" maxlength="32" /><br />
<label>存放文件:</label>
<input type="file" name="file" required />
<input type="submit" value="保存文件!" />
</form>
<div></div>
<script>
//使用下方代码发送请求:
const form = document.forms.namedItem("fileinfo");
form.addEventListener("submit",function(ev){
const oOutput = document.querySelector("div");
const fd = new FormData(form);
fd.append("otherDataKey","This is some extra data");
const xhr = new XMLHttpRequest();
xhr.open("POST",url,true);//url是将要访问的链接地址
xhr.send(fd);
xhr.onload = function(event){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
oOutput.innerHTML = 'Uploaded!';
} else {
oOutput.innerHTML = 'Error' + xhr.status + "在试图上传文件时发生!<br/>";
}
}
ev.preventDefault();
})
</script>
备注:如果 FormData 对象是通过表单创建的,则表单中指定的请求方式会被应用到方法 open() 中。
你还可以直接向 FormData 对象附加 File 或 Blob 类型的文件,如下所示:
js
fd.append("myfile",myBlob,"filename.txt");
使用 append() 方法时,可以通过第三个可选参数设置发送请求的头 Content-Disposition 指定文件名。如果不指定文件名(或者不支持该参数时),将使用名字"blob"。
4. 常用方法
- new FormData():创建一个空的FormData对象。
- append(name, value, [filename]):向FormData对象中添加一个新的字段。name是字段名,value是字段值,filename是可选参数,用于指定当值为文件或Blob对象时的文件名。
- get(name):获取FormData对象中与指定键第一个关联的数据。
- getAll(name):获取FormData对象中与指定键关联的所有数据。
- set(name, value, [filename]):为FormData对象中的指定键设置新的值。如果键已存在,则覆盖原值;如果不存在,则添加新值。
- has(name):判断FormData对象中是否包含某个键。
- delete(name):删除FormData对象中的指定键及其关联的数据。
- keys():返回一个iterator对象,包含FormData对象中的所有键。
- values():返回一个iterator对象,包含FormData对象中的所有值。
- entries():返回一个iterator对象,包含FormData对象中的所有键值对。
由于篇幅过长,案例不在赘述这里我们主要来谈谈append方法和set方法的区别:
append方法
-
功能:
append
方法用于向FormData对象中添加一个新的键值对。如果该键已经存在,它不会覆盖原有值,而是将新值追加到该键对应的值集合中。 -
append
方法接受两个或三个参数。第一个参数是键名(name),第二个参数是键值(value)。第三个参数是可选的,用于指定当键值为文件或Blob对象时的文件名(filename)。 -
示例:
js
const fd = new FormData();
fd.append('username', 'Alice');
fd.append('file', fileInput.files[0], 'profile.jpg');
fd.append('hobbies[]', 'reading');
fd.append('hobbies[]', 'swimming');
在这个例子中,username
键将有一个值'Alice'
,file
键将有一个文件对象,文件名为'profile.jpg'
,而hobbies[]
键将有两个值'reading'
和'swimming'
,这允许服务器接收到一个爱好列表。
set方法
- 功能 :
set
方法也用于向FormData对象中添加或更新数据。但如果指定的键已经存在,set
方法会覆盖该键原有的所有值,而不是追加新值。 - 参数 :
set
方法也接受两个或三个参数。第一个参数是键名(name),第二个参数是键值(value)。第三个参数是可选的,用于指定当键值为文件或Blob对象时的文件名(filename)。 - 示例:
js
const fd = new FormData();
fd.set('username', 'Alice');
fd.set('file', fileInput.files[0], 'profile.jpg');
fd.set('hobbies[]', 'reading');
在这个例子中,如果hobbies[]
键之前已经有值,那么'reading'
将覆盖原有值,而不是追加到列表中。
主要区别总结
append方法 | set方法 | |
---|---|---|
功能 | 追加新值到已存在的键中,或添加新键 | 设置新值,覆盖已存在的键的所有值 |
键存在时 | 保留原有值,并追加新值 | 覆盖原有值,仅保留新值 |
使用场景 | 当你需要向某个键添加多个值时(如文件上传、多选列表) | 当你需要更新某个键的值为单个新值时 |
了解这些区别有助于你在使用FormData对象时根据实际需求选择合适的方法。
3. 设置http请求的时限Timeout
IE8 给 XHR 对象增加了一个 timeout 属性,用于表示发送请求后等待多少毫秒,如果响应不成功就中断请求。之后所有浏览器都在自己的 XHR 实现中增加了这个属性。在给 timeout 属性设置了一个时间且在该时间过后没有收到响应时,XHR 对象就会触发 timeout 事件,调用 ontimeout 事件处理程序。这个特性后来也被添加到了XHR Level 2 规范。
1. 基本用法
xhr.timeout
属性的默认值为0,表示请求没有超时限制。- 当
xhr.timeout
被设置为一个大于0的整数时,它表示请求在自动终止之前可以花费的毫秒数。如果在这个时间内请求没有得到响应,那么请求将被自动终止,并触发ontimeout
事件。 - 示例:
js
const xhr = new XMLHttpRequest();
xhr.open("GET",url, true); //url 将要访问的链接地址
xhr.timeout = 2000; // 设置超时时间为2000毫秒(2秒)
xhr.onload = () => {
// 请求完成后的处理
console.log('Request succeeded');
};
xhr.ontimeout = (e) => {
// 请求超时后的处理
console.error('Request timed out');
};
xhr.send(null);
在这个示例中,如果请求在2秒内没有得到响应,那么将触发ontimeout
事件,并在控制台输出"Request timed out"。
2. 属性值规则
xhr.timeout
属性的值必须是一个整数,表示毫秒数。- 如果设置为0,则表示没有超时限制。
- 如果设置为字符串,且字符串中全部为数字,那么它会自动将字符串转化为数字;如果字符串中包含非数字字符,则该设置不生效。
- 如果设置为对象,且该对象能够转化为数字,那么将设置为转化后的数字;否则,该设置不生效。
3. 注意事项
timeout
属性不应该用于同步XMLHttpRequest请求,否则将抛出InvalidAccessError
异常。- 超时时间的计算是从调用
xhr.send()
方法开始,到请求结束(无论是成功、失败还是超时)为止的这段时间。 - 当
xhr.timeout
触发时,浏览器会自动取消该请求,并触发ontimeout
事件。但请注意,ontimeout
事件处理程序执行完后,请求才会真正被取消。如果ontimeout
事件处理程序执行时间较长,而服务器在此期间已经响应了请求,那么请求将不会被取消。
4. 浏览器兼容性
xhr.timeout
属性在现代浏览器中得到了广泛的支持,包括Chrome、Edge、Firefox、Opera、Safari等。但请注意,在某些旧版本的浏览器中,该属性可能不被支持或存在兼容性问题。
4. overrideMimeType()方法
overrideMimeType()方法是XMLHttpRequest对象(XHR)的一个方法,用于指定在解释请求中传输的数据时要使用的MIME类型,而不是服务器提供的MIME类型。overrideMimeType()方法的详细解释如下:
1. 背景与目的
在Web开发中,XMLHttpRequest对象被广泛应用于客户端与服务器之间的异步通信。然而,在处理从服务器接收到的数据时,有时会遇到MIME类型不匹配或服务器未提供明确MIME类型的情况。这可能导致数据解析错误或无法正确显示数据。为了解决这一问题,overrideMimeType()方法应运而生。
2. 基本用法
- 用法: xhr.overrideMimeType(mimeType)
- 参数: mimeType是一个字符串,指定要使用的MIME类型,而不是服务器指定的类型。
- 调用时机: 此方法必须在调用send() 方法之前调用。
- 示例1:
js
const xhr = new XMLHttpRequest();
xhr.open("GET","/path/assets/img.png",true);
//强制将MIME改为文本类型
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.onreadystatechange = function(e) {
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
const binStr = xhr.responseText;
//将接受到的二进制数据逐个字节还原
for(let i = 0;i<binStr.length;++i){
let c = binStr.charCodeAt(i);
//去掉高位字节,留下低位字节
let byte = c & 0xff;
}
}
}
};
xhr.send(null);
在这个示例中,即使服务器返回的是二进制数据(如图片),通过overrideMimeType()方法将其强制解析为文本类型,然后可以使用responseText属性获取到数据的文本表示,再逐个字节地还原成二进制数据。
- 示例2:
这个例子来自JavaScript高级程序设计(第四版).
假设服务器实际发送了XML数据,但响应头设置的MIME类型是text/plain。结果就会导致虽然数据是XML,但responseXML 属性值是null。此时调用overrideMimeType()可以保证将相应当成XML而不是纯文本来处理:
js
const xhr = new XMLHttpRequest();
xhr.open("GET","text.php",true);
xhr.overrideMimeType("text/xml");
xhr.send(null);
这个例子强制让XHR把响应当成XML而不是纯文本来处理。为了正确覆盖相应的MIME类型,必须在调用send()之前调用overrideMimeType()。
3. 功能与作用
- 覆盖MIME类型: overrideMimeType()方法允许覆盖服务器提供的MIME类型,从而自定义数据的解析方式。例如,即使服务器返回的数据类型是"application/octet-stream",开发者也可以通过overrideMimeType()方法将其强制解析为"text/xml"或"text/plain"。
- 处理二进制数据: 在传统上,如果希望从服务器取回二进制数据,就要使用这个方法,人为将数据类型伪装成文本数据。但这种方法较为繁琐,在XMLHttpRequest版本升级后,一般采用指定responseType属性的方法。
4. 注意事项
- 浏览器兼容性: 大多数现代浏览器都支持此方法,但开发者在使用时仍需注意浏览器的兼容性问题。
- MIME类型和字符集: 在调用overrideMimeType()方法时,可以指定MIME类型和字符集。如果服务器未指定类型,XMLHttpRequest假定为"text/xml"。如果接收到的文本是UTF-8、UTF-16等,浏览器会自动解析,因为会读文件头来确认。
- 避免错误: 如果服务器返回的内容不是有效的XML,而开发者通过overrideMimeType()方法将其强制解析为"text/xml",则可能会发生"XML解析错误:格式不正确"的错误。因此,在使用此方法时需要谨慎选择MIME类型。
5. 与responseType属性的关系
在XMLHttpRequest版本升级后,引入了responseType属性来设置服务器返回数据的类型。与overrideMimeType()方法相比,responseType属性提供了更直接和简便的方式来处理不同类型的返回数据(如文档、JSON、Blob、ArrayBuffer等)。然而,在某些特定场景下(如需要处理二进制数据但又不希望使用responseType属性时),overrideMimeType()方法仍然具有一定的应用价值。
总的来说,overrideMimeType()方法是XMLHttpRequest对象提供的一个强大工具,允许开发者在需要时覆盖服务器提供的MIME类型并自定义数据的解析方式。但在使用时需要注意浏览器兼容性、MIME类型与字符集的选择以及与其他属性(如responseType)的关系。
5 . 进度事件
Progress Events 是 W3C 的工作草案,定义了客户端服务器端通信。这些事件最初只针对 XHR,现
在也推广到了其他类似的 API。有以下 6 个进度相关的事件。
-
loadstart:在接收到响应的第一个字节时触发。
-
progress:在接收响应期间反复触发。
-
error:在请求出错时触发。
-
abort:在调用 abort()终止连接时触发。
-
load:在成功接收完响应时触发。
-
loadend:在通信完成时,且在 error、abort 或 load 之后触发。
每次请求都会首先触发 loadstart 事件,之后是一个或多个 progress 事件,接着是 error、abort
或 load 中的一个,最后以 loadend 事件结束。
这些事件大部分都很好理解,但其中有两个需要说明一下。
1. load事件
在XHR Level 2中,load
事件是一个非常重要的事件,它用于指示XMLHttpRequest请求已成功完成,并且响应数据已经就绪可供使用。以下是对XHR Level 2中load
事件的详细解析:
1.load
事件的基本特性
- 触发时机 :当XMLHttpRequest请求成功完成,并且响应数据已经就绪时,
load
事件会被触发。这意味着你可以在这个事件的处理函数中安全地访问响应数据。 - 事件类型 :
load
事件是一个ProgressEvent类型的事件,这意味着你可以通过事件对象访问与进度相关的属性,尽管对于load
事件来说,这些属性可能不太相关,因为请求已经完成。 - 跨浏览器兼容性 :XHR Level 2是广泛支持的,现代浏览器都实现了这一规范。因此,
load
事件在大多数现代浏览器中都可用。
2. load
事件的使用方法
监听load
事件 :你可以使用addEventListener
方法或直接在XMLHttpRequest对象的onload
属性中指定事件处理函数来监听load
事件。例如:
js
const xhr = new XMLHttpRequest();
xhr.open('GET', 'url', true);
// 使用addEventListener方法监听load事件
xhr.addEventListener('load', function() {
if (xhr.status >= 200 && xhr.status < 300) {
// 请求成功,处理响应数据
console.log(xhr.responseText);
} else {
// 请求失败,处理错误情况
console.error('Request failed with status: ' + xhr.status);
}
});
// 或者直接在onload属性中指定事件处理函数
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
// 请求成功,处理响应数据
console.log(xhr.responseText);
} else {
// 请求失败,处理错误情况
console.error('Request failed with status: ' + xhr.status);
}
};
xhr.send();
3. 与其他事件比较
- 与
readystatechange
事件的比较 :在XHR Level 1中,开发者通常需要监听readystatechange
事件并检查readyState
属性来判断请求的状态(即readyState 是否等于 4)。然而,这种方式相对繁琐,并且需要处理多个状态。相比之下,XHR Level 2中的load
事件提供了一个更简洁的方式来监听请求的成功完成,你只需在load
事件处理函数中处理响应数据即可。 - 与
progress
事件的比较 :progress
事件在请求过程中会多次触发,用于提供数据传输的进度信息。而load
事件只在请求成功完成时触发一次。因此,progress
事件更适合用于实现进度条等功能,而load
事件则用于处理请求完成的逻辑。
4. load
事件处理函数中的常见操作
- 检查响应状态码 :在
load
事件处理函数中,你应该首先检查xhr.status
属性来确定请求是否成功。通常,状态码在200到299之间表示请求成功。 - 处理响应数据 :如果请求成功,你可以通过
xhr.responseText
、xhr.responseXML
或xhr.response
(取决于你设置的responseType
)等属性来访问响应数据。 - 错误处理 :如果请求失败(即状态码不在200到299之间),你应该在
load
事件处理函数中处理错误情况,例如向用户显示错误消息或重试请求。
5. 注意事项
- 确保请求已完成 :在
load
事件处理函数中,你可以安全地假设请求已经完成,并且响应数据已经就绪。但是,在处理响应数据之前,仍然应该检查状态码以确保请求成功。 - 避免重复绑定事件 :如果你多次调用
addEventListener
方法或设置onload
属性来监听load
事件,那么每个事件处理函数都会被触发。因此,你应该确保不会重复绑定事件处理函数。 - 处理跨域请求 :如果你在进行跨域请求,并且服务器没有正确设置CORS(跨源资源共享)头部,那么请求可能会失败,并且
load
事件不会被触发。在这种情况下,你应该监听error
事件来处理跨域请求失败的情况。
总之,load
事件是XHR Level 2中用于指示XMLHttpRequest请求成功完成的重要事件。通过监听load
事件,你可以简化请求完成的逻辑处理,并安全地访问响应数据。
2. progress事件
在XHR Level 2中,progress
事件是一个非常有用的特性,它允许开发者在XMLHttpRequest请求的过程中实时获取数据传输的进度信息。以下是对XHR Level 2中progress
事件的详细解析:
1. progress事件的基本特性
- 触发时机 :
progress
事件在请求的过程中会周期性地触发,具体频率取决于浏览器的实现。它允许开发者在数据传输的任意时刻获取当前的进度信息。 - 事件类型 :
progress
事件是一个ProgressEvent类型的事件。这意味着事件对象将包含与进度相关的额外属性,如loaded
、total
和lengthComputable
。 - 跨浏览器兼容性 :XHR Level 2得到了广泛支持,现代浏览器都实现了这一规范,包括
progress
事件。因此,你可以在这些浏览器中使用progress
事件来监控请求进度。
2. progress
事件的属性
当progress
事件触发时,事件对象将包含以下与进度相关的属性:
loaded
:表示到目前为止已经接收的字节数。total
:表示预期将要接收的总字节数。如果服务器没有提供Content-Length
头部,则此值可能为0。lengthComputable
:一个布尔值,指示是否可以计算进度。如果total
不为0,则此值为true
;否则为false
。
3. progress
事件的使用方法
- 监听
progress
事件: 你可以使用addEventListener方法来监听progress
事件。在事件处理函数中,你可以访问事件对象的loaded
、total
和lengthComputable
属性来获取进度信息。例如:
js
const xhr = new XMLHttpRequest();
xhr.open("GET",`url`,true);
xhr.addEvenListener('progress',function(ev){
if(ev.lengthComplete){
let percentComplete = (ev.loaded / ev.total) * 100;
console.log(percentComplete.toFixed(2)+'% downloaded');
}
});
xhr.send();
- 处理进度信息 :在
progress
事件的处理函数中,你可以根据loaded
和total
属性的值来计算已下载数据的百分比,并更新进度条或其他UI元素以反映当前的下载进度。
4. progress
事件与其他事件的比较
- 与
load
事件的比较 :load
事件在请求成功完成时触发一次,而progress
事件在请求的过程中会周期性地触发多次。load
事件用于处理请求完成的逻辑,而progress
事件则用于提供实时的进度信息。 - 与
readystatechange
事件的比较 :readystatechange
事件在请求状态发生变化时触发。虽然它也可以用于监控请求进度(通过检查readyState
属性),但相比之下,progress
事件提供了更细粒度的进度信息,并且使用起来更加直观。
5. 注意事项
- 确保浏览器支持 :虽然现代浏览器都支持XHR Level 2和
progress
事件,但在一些旧版浏览器或特定环境下,可能仍然需要注意浏览器的兼容性。 - 性能开销 :频繁触发
progress
事件可能会对性能产生一定影响。因此,在需要高性能的应用场景中,应该谨慎使用progress
事件,并考虑使用其他方法来监控请求进度(如使用Web Workers)。 - 处理异常情况 :在
progress
事件的处理函数中,你也应该处理异常情况,例如当lengthComputable
为false
时,无法计算进度信息。此时,你可以向用户显示一个通用的进度指示器(如旋转的加载图标),而不是具体的百分比。
综上所述,progress
事件是XHR Level 2中一个非常有用的特性,它允许开发者在XMLHttpRequest请求的过程中实时获取数据传输的进度信息。通过监听progress
事件并处理进度信息,你可以为用户提供更好的下载体验。
6. 跨域资源共享(CORS)
CORS(Cross-Origin Resource Sharing)是一种机制,它使用额外的HTTP头部来告诉浏览器,允许一个网页从另一个域(不同于该网页所在的域)请求资源。这是为了克服同源策略(Same-Origin Policy)的限制,同源策略是浏览器的一种安全机制,它限制了一个源(协议、域名和端口)的文档或脚本如何能与另一个源的资源进行交互。
由于这部分内容篇幅过长且较为重要,会在之后单独发一篇文章...