🌟 AJAX:让网页"静悄悄"获取数据的魔法
前言:认识AJAX
AJAX (Asynchronous JavaScript and XML) 是前端开发中一项革命性的技术,它让网页能够在不刷新页面的情况下与服务器交换数据并更新部分内容。想象一下:当你在音乐APP点击"新歌速递"时,整个页面不会闪屏刷新,新歌列表就像变魔术一样悄然出现------这就是AJAX的魔力!
AJAX的三大特点:
- 异步通信:不会阻塞用户操作
- 局部更新:只刷新需要变化的部分
- 多种数据格式:不仅限于XML,更常用JSON
正文:手把手教你实现AJAX请求
一、基础AJAX代码解析
我们以获取网易云音乐新歌列表为例:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>音乐速递</title>
</head>
<body>
<button id="btn">新歌速递</button>
<ul id="song-list"></ul>
<script>
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
// 1. 创建XMLHttpRequest对象
let xhr = new XMLHttpRequest();
// 2. 配置请求 (演示用示例地址,实际需替换为真实API)
xhr.open('GET', 'https://api.example.com/top/songs?type=7', true);
// 3. 设置回调函数
xhr.onreadystatechange = () => {
if (xhr.readyState === 4 && xhr.status === 200) {
const result = JSON.parse(xhr.responseText);
// 4. 动态更新DOM
const songList = document.getElementById('song-list');
result.data.forEach(song => {
// console.log(song.name);
let li = document.createElement('li'); // 创建一个 <li> 元素
li.innerHTML = song.name // 将歌曲的名称设置为 <li> 元素的内容
document.getElementById('ul').appendChild(li)
//appendChild添加子元素 将 <li> 元素追加到具有 id 为 'ul' 的元素中
});
}
};
// 5. 发送请求
xhr.send();
});
</script>
</body>
</html>
二、关键知识点详解
1. XMLHttpRequest 对象
new XMLHttpRequest()
:创建请求对象open(method, url, async)
:配置请求GET
/POST
:请求方法- 真实开发中地址应替换为后端提供的API(如:
https://api.music-service.com/v1/songs
) - 第三个参数
true
表示异步(推荐永远用异步!)
2. 请求状态监听
javascript
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
// 请求完成且成功
}
};
-
readyState
:- 0: 请求未初始化
- 1: 服务器连接已建立
- 2: 请求已接收
- 3: 处理请求中
- 4: 请求已完成
-
status
:HTTP状态码(200表示成功)
3. 处理响应数据
xhr.responseText
:获取字符串格式响应JSON.parse()
:将JSON字符串转为JS对象
4. 安全注意事项
-
实际开发中要处理错误情况:
javascriptif (xhr.status >= 200 && xhr.status < 300) { // 成功处理 } else { console.error('请求失败:', xhr.statusText); }
-
跨域问题:如果API与网页不同源,需要后端配置CORS
三、改进
如果我们要进行多次前后端联调,那上面这段代码不是有点麻烦吗,有没有更优雅一点代码呢,当然有,看下面代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">新歌速递</button>
<ul id="ul">
</ul>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
$.ajax({
url: 'https://api.example.com/top/songs?type=7',
method: 'GET',
dataType: 'json',
success: function (res) {
console.log(res);
// 然后完成接下来的逻辑
}
})
})
</script>
</body>
</html>
这两段代码的主要区别在于实现AJAX请求的方式不同:现在使用jQuery的$.ajax()
方法,前面那段使用原生JavaScript的XMLHttpRequest
对象。以下是第一段代码的优势分析:
1. 代码简洁性和可读性
-
jQuery版本 :代码更加简洁,只需要配置一个对象参数即可完成请求,逻辑清晰。
javascript$.ajax({ url: '...', method: 'GET', dataType: 'json', success: function(res) { ... } });
-
原生版本 :需要手动创建
XMLHttpRequest
对象,处理readyState
和status
,代码量更多,逻辑分散。javascriptlet xhr = new XMLHttpRequest(); xhr.open('GET', '...', true); xhr.onreadystatechange = () => { ... }; xhr.send();
2. 自动处理JSON解析
- jQuery版本 :通过设置
dataType: 'json'
,jQuery会自动将响应数据解析为JSON对象,无需手动调用JSON.parse()
。 - 原生版本 :需要手动调用
JSON.parse(xhr.responseText)
解析响应数据。
3. 跨浏览器兼容性
- jQuery版本:jQuery内部处理了不同浏览器的兼容性问题(如早期的IE),开发者无需关心底层差异。
- 原生版本 :可能需要额外代码处理不同浏览器的兼容性(如
ActiveXObject
)。
4. 错误处理
-
jQuery版本 :可以通过
error
或fail
回调统一处理错误,例如:javascript$.ajax({ ... error: function(xhr, status, error) { ... } });
-
原生版本 :需要在
onreadystatechange
中检查xhr.status
,错误处理逻辑分散。
5. 链式调用和扩展性
-
jQuery版本 :支持Promise风格的链式调用(如
.done()
,.fail()
),便于扩展和维护。javascript$.ajax({...}).done(function(res) {...}).fail(function() {...});
-
原生版本:需要自行封装Promise或使用回调函数,扩展性较差。
6. 其他功能
-
jQuery版本 :支持更高级的功能(如请求超时、全局事件、请求取消等),只需配置参数即可。
javascript$.ajax({ timeout: 5000, // 超时设置 beforeSend: function() { ... } // 发送前回调 });
-
原生版本:需要手动实现这些功能。
原生版本的优势
虽然jQuery版本更简洁,但原生版本也有其优势:
- 无依赖:不依赖第三方库,减少页面加载资源。
- 性能:直接使用浏览器API,理论上性能更高(但差异通常很小)。
- 学习价值:理解原生实现有助于掌握底层原理。
那还能改进吗,当然,再看接下来的代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">新歌速递</button>
<ul id="ul">
</ul>
<script>
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
fetch('http://192.168.31.45:3000/top/song?type=7')
.then(data => data.json())
.then(res => {
console.log(res);
})
})
</script>
</body>
</html>
这段代码使用了现代JavaScript的 fetch
API 来实现AJAX请求,相比之前的 jQuery $.ajax()
和 原生 XMLHttpRequest
,它有以下优势和不同之处:
1. fetch
API 的优势
✅ 更现代、更简洁
fetch
是ES6引入的现代API,语法更简洁,基于 Promise,避免了回调地狱(Callback Hell)。- 相比
XMLHttpRequest
,代码量更少;相比$.ajax()
,它是原生API,无需引入jQuery。
✅ Promise 链式调用
fetch
返回一个 Promise ,可以使用.then()
和.catch()
进行链式调用,逻辑更清晰。- 而
XMLHttpRequest
使用回调函数,$.ajax()
虽然支持Promise,但fetch
是原生支持。
✅ 更灵活的请求和响应处理
-
fetch
的响应是一个Response
对象 ,可以方便地读取JSON、文本、Blob等格式:jsfetch(url) .then(response => response.json()) // 解析JSON .then(data => console.log(data)) .catch(error => console.error(error));
-
XMLHttpRequest
需要手动解析xhr.responseText
,而fetch
提供了.json()
,.text()
,.blob()
等方法。
✅ 默认不携带Cookie,更安全
fetch
默认不会发送或接收Cookies(除非设置credentials: 'include'
),安全性更高。XMLHttpRequest
和$.ajax()
默认行为可能不同,需要额外配置。
2. 对比之前的方案
特性 | fetch API |
$.ajax() (jQuery) |
XMLHttpRequest |
---|---|---|---|
语法简洁性 | ⭐⭐⭐(Promise风格) | ⭐⭐(配置对象) | ⭐(回调方式) |
是否需要库 | ❌ 原生支持 | ✅ 依赖jQuery | ❌ 原生支持 |
Promise支持 | ✅ 原生支持 | ✅(jQuery 3.0+) | ❌(需手动封装) |
JSON解析 | response.json() |
自动(dataType: 'json' ) |
手动JSON.parse() |
错误处理 | .catch() |
.fail() 或 error 回调 |
手动检查xhr.status |
跨域请求控制 | credentials: 'include' |
xhr.withCredentials = true |
xhr.withCredentials = true |
浏览器兼容性 | 现代浏览器(IE不支持) | 广泛支持(包括旧版IE) | 广泛支持 |
3. fetch
的潜在缺点
❌ 不直接支持超时(需手动封装)
fetch
本身没有超时参数,但可以用 Promise.race()
实现:
js
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("请求超时")), 5000)
);
Promise.race([fetch(url), timeout])
.then(response => response.json())
.catch(error => console.error(error));
而 $.ajax()
和 XMLHttpRequest
可以直接设置 timeout
。
❌ 默认不处理HTTP错误状态
fetch
只有在 网络错误 (如CORS、DNS失败)时才会 reject
,而 HTTP 404/500 仍然会进入 .then()
,需要手动检查:
js
fetch(url)
.then(response => {
if (!response.ok) throw new Error("HTTP错误: " + response.status);
return response.json();
})
.catch(error => console.error(error));
而 $.ajax()
和 XMLHttpRequest
可以自动处理HTTP错误。
❌ IE完全不支持
如果需要兼容IE,必须使用 XMLHttpRequest
或 $.ajax()
。
4. 代码改进建议
如果想更健壮地使用 fetch
,可以这样写:
js
btn.addEventListener('click', async () => {
try {
const response = await fetch('http://192.168.31.45:3000/top/song?type=7');
if (!response.ok) throw new Error("请求失败: " + response.status);
const res = await response.json();
console.log(res);
// 渲染歌曲列表
res.data.forEach(song => {
const li = document.createElement('li');
li.textContent = song.name;
document.getElementById('ul').appendChild(li);
});
} catch (error) {
console.error("请求出错:", error);
}
});
- 使用
async/await
让代码更易读。 - 检查
response.ok
确保HTTP请求成功。 - 错误处理更完善。
总结
方案 | 适用场景 |
---|---|
fetch |
现代浏览器、简洁Promise风格、无需jQuery |
$.ajax() |
需要兼容旧浏览器、习惯jQuery、需要高级功能(如自动重试) |
XMLHttpRequest |
需要最大兼容性(如IE)、无依赖、学习底层原理 |
推荐选择:
- 现代项目优先用
fetch
(代码更简洁,未来趋势)。 - 旧项目或需要兼容IE用
$.ajax()
或XMLHttpRequest
。 - 如果已经用了jQuery,
$.ajax()
仍然是不错的选择。