Ajax
AJAX(Asynchronous JavaScript and XML)即异步 JavaScript 和 XML,用于在不刷新页面的情况下与服务器进行数据交互。
1. 特性
1.1 异步性
可以在不阻塞用户界面操作的情况下进行数据交互。
1.2 局部刷新
能够仅更新页面的特定部分,而不是整个页面重新加载。
1.3 增强用户体验
让用户感觉应用更加流畅和响应迅速。
1.4 按需交换数据
只交换页面需要的数据时,可能减少传输和重复渲染;请求过多或接口设计不当仍可能降低性能。
1.5 及时更新
可以按事件或定时请求最新数据,但 AJAX 本身不是实时推送机制;实时双向通信通常使用 WebSocket,单向推送还可使用 Server-Sent Events。
2. 使用步骤
- 创建
XMLHttpRequest对象 - 通过
open()初始化请求方法、URL 等参数;它不会立即建立网络连接 - 构建请求所需的数据内容,并通过
XMLHttpRequest对象的send()方法发送给服务器端 - 通过
XMLHttpRequest对象提供的readystatechange、loadend事件监听服务器端的通信状态 - 接受并处理服务端向客户端响应的数据结果
- 将处理结果更新到
HTML页面中
3. 代码示例
3.1 GET 请求示例
const btn = document.getElementById("btn");
const ul = document.getElementById("list");
btn.addEventListener("click", () => {
// 朝一个接口发请求,获取到数据展示到页面上
const xhr = new XMLHttpRequest(); // 创建一个 ajax 实例
xhr.open("GET", "https://example.com/api/list", true);
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
const res = xhr.responseText; // 拿到后端返回的数据
const data = JSON.parse(res); // 解析 JSON
const movieList = data.movieList;
for (let index = 0; index < movieList.length; index++) {
const li = document.createElement("li");
li.innerText = movieList[index].nm + "--" + movieList[index].star;
ul.appendChild(li);
}
}
};
});3.2 POST 请求示例
// 本例发送 JSON,因此显式设置对应的 Content-Type
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://xxx/api/register");
xhr.addEventListener("readystatechange", () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// 在这里处理服务器的响应数据
console.log(xhr.response);
}
});
xhr.setRequestHeader("Content-Type", "application/json");
const obj = {
username: "xxx",
password: "xxx",
};
xhr.send(JSON.stringify(obj));3.3 简化写法
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://xxxx.com/xxx/xxx?参数名1=值1&参数名2=值2");
xhr.addEventListener("loadend", () => {
// loadend 在成功、失败或中止后都会触发,仍需检查 status 或分别监听 load/error
if (xhr.status >= 200 && xhr.status < 300) {
console.log(xhr.response);
}
});
xhr.send();3.4 旧写法 vs 新写法
// 旧写法
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300) {
// 在这里处理服务器的响应数据
console.log(xhr.responseText);
} else {
// 这里只处理请求完成后的 HTTP 错误,不会在中间状态重复报错
console.log(xhr.statusText);
}
};
// 新写法
xhr.addEventListener("readystatechange", () => {
if (xhr.readyState === 4 && xhr.status === 200) {
// 在这里处理服务器的响应数据
console.log(xhr.response);
}
});4. 参数说明
4.1 open()
open() 只初始化请求;真正的网络请求由 send() 启动。
语法:xhr.open(method, url, [async])
| 参数 | 描述 |
|---|---|
| method | 表示当前的请求方式,常见的有 GET、POST |
| url | 服务端地址 |
| async | 布尔值,表示是否异步执行操作,默认为 true(异步) |
4.2 send()
通过 XMLHttpRequest 对象的 send() 方法,将客户端页面的数据发送给服务端。
语法:xhr.send([body])。body 除字符串外,还可以是 FormData、Blob、ArrayBuffer、URLSearchParams、Document 等受支持类型;无请求体时省略或传 null。
4.3 onreadystatechange
每当 readyState 实际发生变化时会触发 readystatechange。不要依赖固定触发次数;只需判断是否到达 DONE(值为 4),或按需使用 load、error、abort、timeout 等事件。
4.3.1 XMLHttpRequest 对象的三个重要属性
| 属性 | 描述 |
|---|---|
| onreadystatechange | 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数 |
| readyState | 存有 XMLHttpRequest 的状态 |
| status | 200: "OK",404: 未找到页面 |
4.3.2 readyState 的取值(ajax 的状态)
- 0 — xhr 刚创建
- 1 — open 执行
- 2 — 已接收响应状态和响应头
- 3 — 正在接收响应体,可能已有部分数据
- 4 — 请求操作完成(无论 HTTP 状态是否成功)
4.4 服务器响应
获取 XMLHttpRequest 响应体。
5. GET 和 POST 对比
GET 与 POST 的核心差异是 HTTP 语义,不是固定的速度或安全级别:
- GET 用于获取资源,是安全且幂等的方法;其 URI 可能出现在历史、日志和缓存键中,不应把敏感数据放进查询串
- POST 让目标资源处理请求内容,通常非幂等;协议允许缓存 POST 响应,但实践中需要明确的缓存配置
- HTTP 没有规定“POST 请求体无限大”。浏览器、代理、Web 服务器和应用都可以设置大小上限;GET 的 URI 长度也常受各层实现限制
- 是否设置
Content-Type取决于请求体格式。发送 JSON 或表单编码文本时应设置;发送FormData时不要手写该头,否则容易遗漏浏览器生成的boundary
6. FormData
模拟表单,适合用于发送包含文件上传等复杂数据的请求。
使用 FormData 可以执行以下步骤:
6.1 创建 FormData 对象
const formData = new FormData();6.2 向 FormData 对象中添加字段
formData.append("username", "John");
formData.append("email", "john@example.com");6.3 添加文件类型的字段
// 从文件输入框中获取选中的文件,可以根据实际情况选择获取文件的方式
const fileInput = document.getElementById("fileInput");
formData.append("file", fileInput.files[0]);6.4 将 FormData 对象作为请求的 body
const xhr = new XMLHttpRequest();
xhr.open("POST", "/api/endpoint");
xhr.send(formData);6.5 注意事项
- 当使用 FormData 时,浏览器会自动设置适当的
Content-Type头部,无需手动设置 - FormData 也支持删除字段和追加相同字段名的多个值等操作
6.6 参考资料
FormData 对象的使用 - Web API | MDN (mozilla.org)
FormData - Web API | MDN (mozilla.org)
7. 封装 ajax
// 使用的时候直接调用,传递一个对象就可以
ajax({
url: "", // 请求的地址
type: "", // 请求方式
async: "", // 是否异步
data: "", // 携带的参数
dataType: "", // 要不要执行 JSON.parse
success: function () {}, // 成功以后执行的函数
});7.1 简单封装示例
function ajax(options) {
const xhr = new XMLHttpRequest();
// 处理参数
let params = "";
if (options.data) {
const arr = [];
for (const key in options.data) {
arr.push(encodeURIComponent(key) + "=" + encodeURIComponent(options.data[key]));
}
params = arr.join("&");
}
let url = options.url;
if (options.type.toUpperCase() === "GET" && params) {
url += "?" + params;
}
xhr.open(options.type, url, options.async ?? true);
if (options.type.toUpperCase() === "POST") {
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(params);
} else {
xhr.send();
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
let res = xhr.responseText;
if (options.dataType === "json") {
res = JSON.parse(res);
}
options.success && options.success(res);
}
};
}8. 使用 XMLHttpRequest 对象
- 获取页面上的按钮元素和列表元素
- 为按钮添加点击事件监听
- 在点击事件处理函数中:
- 创建 XMLHttpRequest 对象用于进行 AJAX 请求
- 配置请求方法、请求地址和异步方式
- 发送请求
- 监听请求状态变化
- 当请求状态为 4 且状态码为 200 时(表示请求成功):
- 获取响应文本
- 将响应文本解析为 JSON 对象
- 通过遍历数据,创建列表项元素并添加到列表中展示
9. Fetch API(补充)
Fetch 是现代浏览器提供的原生 AJAX 替代方案,基于 Promise。
9.1 基本用法
fetch("https://api.example.com/data")
.then((response) => {
// Fetch 只会因网络层失败而 reject,404/500 仍会 resolve。
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then((data) => console.log(data))
.catch((error) => console.error(error));9.2 POST 请求
fetch("https://api.example.com/data", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "John", age: 25 }),
})
.then((response) => response.json())
.then((data) => console.log(data));9.3 async/await 写法
async function fetchData() {
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}9.4 Fetch 的优点
- Promise 风格,链式调用更优雅
- 语法简洁
- 可以与现代 async/await 结合
- 内置支持 FormData、Blob、JSON 等多种格式