Ajax 技术与实现
理解 Ajax 原理,掌握 XMLHttpRequest 和 Fetch API 的使用
问题
什么是 Ajax?如何使用原生 JavaScript 实现 Ajax 请求?
解答
Ajax(Asynchronous JavaScript and XML)是一种在不刷新页面的情况下与服务器交换数据的技术。
XMLHttpRequest 方式
// 封装 XMLHttpRequest
function ajax(options) {
const { method = 'GET', url, data = null, headers = {} } = options;
return new Promise((resolve, reject) => {
// 1. 创建 XMLHttpRequest 对象
const xhr = new XMLHttpRequest();
// 2. 初始化请求
xhr.open(method, url, true);
// 3. 设置请求头
Object.keys(headers).forEach(key => {
xhr.setRequestHeader(key, headers[key]);
});
// 4. 监听状态变化
xhr.onreadystatechange = function() {
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
reject(new Error(`Request failed with status ${xhr.status}`));
}
};
// 5. 错误处理
xhr.onerror = function() {
reject(new Error('Network error'));
};
// 6. 超时处理
xhr.timeout = 10000;
xhr.ontimeout = function() {
reject(new Error('Request timeout'));
};
// 7. 发送请求
xhr.send(data ? JSON.stringify(data) : null);
});
}
// 使用示例
ajax({
method: 'GET',
url: 'https://api.example.com/users'
}).then(data => {
console.log(data);
}).catch(err => {
console.error(err);
});
Fetch API 方式
// 封装 Fetch
async function request(url, options = {}) {
const {
method = 'GET',
data = null,
headers = {},
timeout = 10000
} = options;
// 创建 AbortController 用于超时控制
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
...headers
},
body: data ? JSON.stringify(data) : null,
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('Request timeout');
}
throw error;
}
}
// GET 请求
const users = await request('https://api.example.com/users');
// POST 请求
const newUser = await request('https://api.example.com/users', {
method: 'POST',
data: { name: 'John', age: 25 }
});
XMLHttpRequest 的 readyState
| 值 | 状态 | 说明 |
|---|---|---|
| 0 | UNSENT | 对象已创建,未调用 open |
| 1 | OPENED | open 已调用 |
| 2 | HEADERS_RECEIVED | 收到响应头 |
| 3 | LOADING | 正在接收响应体 |
| 4 | DONE | 请求完成 |
处理并发请求
// 并行请求
async function parallel(urls) {
const promises = urls.map(url => request(url));
return Promise.all(promises);
}
// 串行请求
async function serial(urls) {
const results = [];
for (const url of urls) {
results.push(await request(url));
}
return results;
}
// 控制并发数量
async function limitConcurrency(urls, limit = 3) {
const results = [];
const executing = [];
for (const url of urls) {
const p = request(url).then(res => {
executing.splice(executing.indexOf(p), 1);
return res;
});
results.push(p);
executing.push(p);
if (executing.length >= limit) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
关键点
- XMLHttpRequest 是传统方式,通过
readyState和status判断请求状态 - Fetch API 是现代方式,基于 Promise,语法更简洁
- Fetch 不会因 HTTP 错误状态码(如 404、500)而 reject,需要手动检查
response.ok - Fetch 原生不支持超时,需要配合
AbortController实现 - 跨域请求需要服务端配置 CORS 或使用代理
目录