一、什么是 Ajax?
Ajax(Asynchronous JavaScript and XML) 是一种在不重新加载整个页面的情况下,通过 JavaScript 异步与服务器交换数据并更新部分网页内容的技术。虽然名字中包含 XML,但现代 Ajax 更常使用 JSON 格式进行数据交互。
✅ 核心价值:提升用户体验,实现"局部刷新",避免整页跳转。
二、Ajax 的核心流程(基于 XMLHttpRequest)
XMLHttpRequest(简称 XHR)是浏览器原生提供的用于发起 HTTP 请求的 API。以下是其标准使用流程:
1. 创建请求对象
ini
javascript
编辑
const xhr = new XMLHttpRequest();
2. 配置请求(open)
kotlin
javascript
编辑
xhr.open(method, url, async);
// 示例:
xhr.open('GET', 'https://api.github.com/orgs/lemoncode/members', true); // 推荐异步
method:请求方法(GET、POST 等)url:目标接口地址async:是否异步(强烈建议设为true,避免阻塞主线程)
⚠️ 注意:你的原始代码中使用了
false(同步),这会导致浏览器卡死,生产环境严禁使用同步请求!
3. 设置事件监听器(onreadystatechange)
ini
javascript
编辑
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
// 更新 DOM
}
};
readyState 状态说明:
| 值 | 状态 | 含义 |
|---|---|---|
| 0 | UNSENT | 请求未初始化(刚创建) |
| 1 | OPENED | open() 已调用 |
| 2 | HEADERS_RECEIVED | send() 已调用,响应头已接收 |
| 3 | LOADING | 响应体正在接收中 |
| 4 | DONE | 请求完成(成功或失败) |
✅ 只有当
readyState === 4且status === 200时,才表示请求成功完成。
4. 发送请求(send)
scss
javascript
编辑
xhr.send(); // GET 请求通常无参数;POST 可传 body 数据
三、完整示例修正版(推荐写法)
xml
html
预览
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax 数据请求(修正版)</title>
</head>
<body>
<ul id="members"></ul>
<script>
const xhr = new XMLHttpRequest();
// 推荐:使用异步请求(async = true)
xhr.open('GET', 'https://api.github.com/orgs/lemoncode/members', true);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
try {
const members = JSON.parse(xhr.responseText);
document.getElementById('members').innerHTML =
members.map(m => `<li>${m.login}</li>`).join('');
} catch (e) {
console.error('JSON 解析失败:', e);
}
} else {
console.error('请求失败,状态码:', xhr.status);
}
}
};
xhr.send();
</script>
</body>
</html>
✅ 修正点:
- 改为 异步请求 (
true)- 增加 错误处理(状态码非 200、JSON 解析异常)
- 移除冗余的
console.log,聚焦核心逻辑
四、现代替代方案:fetch API
虽然 XHR 仍广泛使用,但现代开发更推荐使用 fetch ------ 基于 Promise 的新标准:
ini
javascript
编辑
fetch('https://api.github.com/orgs/lemoncode/members')
.then(response => {
if (!response.ok) throw new Error('网络响应失败');
return response.json();
})
.then(members => {
document.getElementById('members').innerHTML =
members.map(m => `<li>${m.login}</li>`).join('');
})
.catch(err => console.error('请求出错:', err));
✅ 优势:语法简洁、天然支持 Promise、更易链式调用
❌ 劣势:对 IE 不友好(需 polyfill)
五、常见问题与最佳实践
| 问题 | 解决方案 |
|---|---|
| 跨域请求失败 | 后端配置 CORS,或使用代理 |
| 同步请求卡死页面 | 永远不要用 async: false |
| JSON 解析错误 | 使用 try...catch 包裹 JSON.parse |
| 内存泄漏 | 在 SPA 中注意取消未完成的请求(可用 AbortController) |
六、大厂高频 Ajax 面试题(附答案)
1. Ajax 和 fetch 的区别是什么?
答:
XMLHttpRequest是传统 API,回调风格,需手动监听状态;fetch是基于 Promise 的现代 API,语法更简洁,但默认不处理 4xx/5xx 错误(需手动检查response.ok);fetch不支持超时控制(需配合AbortController),而 XHR 可通过timeout属性设置。
2. 为什么 Ajax 默认不能跨域?如何解决?
答 : 出于浏览器同源策略安全限制。解决方案包括:
- 后端设置 CORS 头(如
Access-Control-Allow-Origin: *)- 开发阶段使用 Webpack/Vite 代理
- JSONP(仅限 GET,已过时)
- Nginx 反向代理
3. 如何取消一个正在进行的 Ajax 请求?
答:
XHR :调用
xhr.abort();fetch :使用
AbortController:
scssjs 编辑 const controller = new AbortController(); fetch(url, { signal: controller.signal }); // 取消 controller.abort();
4. Ajax 请求中,readyState 和 status 的区别?
答:
readyState表示请求生命周期阶段(0~4);status表示HTTP 响应状态码(如 200、404、500);- 必须同时满足
readyState === 4且status === 200才算成功。
5. 同步 Ajax 有什么问题?为什么禁止使用?
答 : 同步请求会阻塞浏览器主线程,导致页面"假死",用户无法交互,严重损害体验。现代浏览器已废弃同步 XHR(尤其在主线程中)。
6. 如何处理 Ajax 的错误?
答:
- XHR:监听
onerror事件 + 检查status !== 200- fetch:
.catch()捕获网络错误 + 检查response.ok- 统一错误提示、重试机制、日志上报
七、总结
Ajax 是前端与后端通信的基石技术。掌握 XMLHttpRequest 的底层原理,有助于理解现代 fetch、axios 等封装库的设计思想。在实际开发中:
✅ 坚持异步
✅ 做好错误处理
✅ 优先使用 fetch 或 axios
✅ 理解跨域与安全机制
只有夯实基础,才能在复杂场景中游刃有余,轻松应对大厂面试挑战!
📌 延伸学习:
- MDN: XMLHttpRequest
- Fetch API 规范
- Axios 源码解析(基于 XHR 封装)