文章目录
1. AJAX简介
Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
1.1. 特点
- 在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
- 不需要任何浏览器插件,但需要用户允许 JavaScript 在浏览器上执行。
1.2. XMLHttpRequest
1.2.1. XMLHttpRequest简介
XMLHttpRequest 是实现 AJAX 的一种方式。
官网地址: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
1.2.2. XMLHttpRequest实例与属性
let xhr = new XMLHttpRequest()
XMLHttpRequest.readyState属性返回XMLHttpRequest客户端所处的状态。XHR客户端处于以下状态之一:
示例代码
const xhr = new XMLHttpRequest();
console.log("UNSENT", xhr.readyState); // readyState will be 0
xhr.open("GET", "/api", true);
console.log("OPENED", xhr.readyState); // readyState will be 1
xhr.onprogress = () => {
console.log("LOADING", xhr.readyState); // readyState will be 3
};
xhr.onload = () => {
console.log("DONE", xhr.readyState); // readyState will be 4
};
xhr.send(null);
XMLHttpReques实例的 response 属性以ArrayBuffer、Blob、Document、JavaScript对象或字符串的形式返回响应的主体内容,具体取决于请求的 responseType 属性的值。
-
XMLHttpRequest.responseText (只读)
返回一个字符串,该字符串以文本形式包含对请求的响应,如果请求未成功或尚未发送,则返回null。其他形式包括 XMLHttpRequest.responseXML,XMLHttpRequest.responseURL
-
XMLHttpRequest.responseType
-
XMLHttpRequest.status (只读)
只读的XMLHttpRequest.status属性返回XMLHttpRequest响应的数字HTTP状态代码。
-
XMLHttpRequest.timeout
请求在自动终止之前可能花费的时间(以毫秒为单位)。
-
XMLHttpRequest.upload
XMLHttpRequest.upload返回一个XMLHttpRequestUpload对象,可以观察该对象来监视上传的进度。
它是一个不透明的对象,但因为它也是一个XMLHttpRequestEventTarget,所以可以附加事件侦听器来跟踪其进程。
1.2.2. XMLHttpRequest方法
-
abort()
如果请求已经发送,XMLHttpRequest.abort()方法会中止该请求。当请求中止时,其readyState将更改为XMLHttpRequest.UNSENT(0),并且请求的状态代码设置为0。
-
getAllResponseHeaders()
返回值为一个字符串,由CRLF分隔的所有响应标头(字段名为Set Cookie的标头除外),如果未收到响应,则为null。如果发生网络错误,将返回一个空字符串。
getResponseHeader(headerName) const contentType = client.getResponseHeader("Content-Type");
-
open()
初始化新创建的请求,或重新初始化现有请求
open(method, url) open(method, url, async) open(method, url, async, user) open(method, url, async, user, password)
- method
要使用的HTTP请求方法,如“GET”、“POST”、“PUT”、“DELETE”等。对于非HTTP(S)URL忽略。 - url
一个字符串或任何其他带有字符串标识符URL的对象,它提供了发送请求的资源的URL。 - async
一个可选的布尔参数,默认为true,指示是否异步执行操作。如果该值为false,send()方法在收到响应之前不会返回。如果为true,则使用事件侦听器提供已完成事务的通知。如果multipart属性为true,则必须为true,否则将引发异常。 - user, password
用于身份验证的可选用户名;默认情况下,这是null值。
- method
-
send()
XMLHttpRequest.send()将请求发送到服务器。如果请求是异步的(这是默认的),则在发送请求并使用事件传递结果后,此方法立即返回。如果请求是同步的,则此方法在响应到达之前不会返回。send()接受一个可选参数,用于指定请求的主体;这主要用于PUT等请求。如果请求方法是GET或HEAD,则会忽略body参数,并将请求正文设置为null。如果使用setRequestHeader()未设置Accept标头,则会发送类型为“/”(任何类型)的Accept标头。
send() send(body)
body的取值
-
body可以是一个序列化的 Document
-
一个 XMLHttpRequestBodyInit 根据Fetch规范,它可以是ArrayBuffer、Blob、TypedArray、DataView、FormData、URLSearchParams或字符串文字或对象。
-
null,默认值
-
note:发送二进制内容(例如文件上传)的最佳方式是将TypedArray、DataView或Blob对象与send()方法结合使用。
返回值:None (undefined).
报错信息:
InvalidStateError DOMException
如果已经为请求调用了send(),或请求已完成。
NetworkError DOMException
如果要获取的资源类型是Blob,并且方法不是GET。 -
-
setRequestHeader()
必须在send()之前,open()方法之后调用,出于安全原因,有几个被禁止的请求头名称,其值由用户代理控制。任何从前端JavaScript代码为其中一个请求头设置值的尝试都将被忽略,不会发出警告或出现错误。此外,Authorization HTTP请求头名可以添加到请求中,但如果请求被跨源重定向,则会被删除。
setRequestHeader(header, value)
1.2.3. XMLHttpRequest事件监听
Event | Event properties | 触发条件 |
---|---|---|
abort | lengthComputable,loaded,total | abort event 是在请求被中止时触发的,例如XMLHttpRequest实例调用 abort() 方法 |
error | lengthComputable,loaded,total | 当请求遇到错误时,会激发错误事件。 |
loadend | lengthComputable,loaded,total | 当请求完成时,无论是成功(加载后)还是失败(中止或出错后),都会触发loadend事件 |
load | lengthComputable,loaded,total | 当XMLHttpRequest事务成功完成时,将触发加载事件。 |
loadstart | lengthComputable,loaded,total | 当请求开始加载数据时,会触发loadstart事件。 |
progress | lengthComputable,loaded,total | 当请求接收到更多数据时,会定期触发进度事件。 |
readystatechange | lengthComputable,loaded,total | 只要XMLHttpRequest的readyState属性发生更改,就会触发readystatechange事件。 |
timeout | lengthComputable,loaded,total | 当进程由于预设时间到期而终止时,会触发超时事件。 |
- lengthComputable:boolean,表示程序进程进度是否是可计算的(可测量的)。
- loaded:64-bit unsigned integer,表示底层进程已执行的工作量。以完成工作比率可以通过将loaded / total计算。当使用HTTP下载资源时,loaded 只计算HTTP消息的正文,不包括请求头和其他开销。
- total:64-bit unsigned integer,表示底层进程正在执行的总工作量。当使用HTTP下载资源时,total 只表示 Content-Length(消息正文的大小),不包括请求头和其他开销。
- 语法示例:
addEventListener("abort", (event) => {}); onabort = (event) => {}; addEventListener("error", (event) => {}); onerror = (event) => {};
2. XMLHttpRequest Demo
2.1. Demo1 progress event
<div class="controls">
<input
class="xhr success"
type="button"
name="xhr"
value="Click to start XHR (success)" />
<input
class="xhr error"
type="button"
name="xhr"
value="Click to start XHR (error)" />
<input
class="xhr abort"
type="button"
name="xhr"
value="Click to start XHR (abort)" />
</div>
<textarea readonly class="event-log"></textarea>
const xhrButtonSuccess = document.querySelector(".xhr.success");
const xhrButtonError = document.querySelector(".xhr.error");
const xhrButtonAbort = document.querySelector(".xhr.abort");
const log = document.querySelector(".event-log");
function handleEvent(e) {
log.textContent = `${log.textContent}${e.type}: ${e.loaded} bytes transferred\n`;
}
function addListeners(xhr) {
xhr.addEventListener("loadstart", handleEvent);
xhr.addEventListener("load", handleEvent);
xhr.addEventListener("loadend", handleEvent);
xhr.addEventListener("progress", handleEvent);
xhr.addEventListener("error", handleEvent);
xhr.addEventListener("abort", handleEvent);
}
function runXHR(url) {
log.textContent = "";
const xhr = new XMLHttpRequest();
addListeners(xhr);
xhr.open("GET", url);
xhr.send();
return xhr;
}
xhrButtonSuccess.addEventListener("click", () => {
runXHR(
"https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json",
);
});
xhrButtonError.addEventListener("click", () => {
runXHR("http://i-dont-exist");
});
xhrButtonAbort.addEventListener("click", () => {
runXHR(
"https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json",
).abort();
});
2.1. Demo2 XMLHttpRequest 上传图片
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.image-upload{
display:inline-block;
position: relative;
}
.image-upload__input {
display: none;
}
.image-upload__thumbnail {
width: 100px;
height: 100px;
border: 1px solid black;
}
.image-upload__body {
position: relative;
display: inline-block;
height: 100%;
}
.image-upload__background {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.image-upload__progress{
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
width: auto;
margin: auto 0;
}
.is-not-uploading{
display: none;
}
</style>
</head>
<body>
<div class="image-upload">
<label for="up-image" class="image-upload__body">
<img alt="上传文件" id="image" src="缺省页_上传中.svg" class="image-upload__thumbnail">
<div class="image-upload__background is-not-uploading">
<progress class="image-upload__progress "></progress>
</div>
</label>
<input id="up-image" type="file" accept="image/*" class="image-upload__input">
</div>
<script>
let imageUploadThumbnail = document.querySelector('.image-upload__thumbnail');
let imageUploadInput = document.querySelector('.image-upload__input');
let imageUploadBackground = document.querySelector('.image-upload__background');
let imageUploadProgress = document.querySelector('.image-upload__progress');
imageUploadInput.onchange = function(){
let formData = new FormData();
let file = this.files[0];
let xhr = new XMLHttpRequest();
if(!file){
return ;
}
formData.set('file',file);
imageUploadThumbnail.src = URL.createObjectURL(file);//在控件内显示选中图片
imageUploadBackground.classList.remove("is-not-uploading");
xhr.upload.onprogress = function(e){
imageUploadProgress.value = e.loaded;
imageUploadProgress.max = e.total;
};
xhr.onloadend = function(){
imageUploadThumbnail.src="缺省页_上传中.svg";
imageUploadBackground.classList.add("is-not-uploading");
}
xhr.open("POST",'http://192.168.36.115:8080/common/upload');
xhr.send(formData);
console.log("请求发送中");
}
</script>
</body>
</html>