fetch 和 AJAX 都是用于浏览器与服务器通信的技术,但它们在设计理念、使用方式和功能特性上有显著区别。以下是两者的详细对比:
1. 核心概念
| 特性 | Fetch API | AJAX(XMLHttpRequest) |
|---|---|---|
| 技术本质 | 现代浏览器原生 API(基于 Promise) | 早期的浏览器 API(基于事件回调) |
| 语法风格 | Promise 链式调用,更简洁 | 事件监听 + 回调函数,代码冗长 |
| 诞生时间 | ES6(2015年)引入 | 1999年由微软提出,2006年标准化 |
2. 代码对比
AJAX(XMLHttpRequest)
javascript
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data');
xhr.onload = function() {
if (xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
} else {
console.error('请求失败');
}
};
xhr.onerror = function() {
console.error('网络错误');
};
xhr.send();
- 缺点:
- 回调嵌套复杂(“回调地狱”)。
- 需手动处理响应状态码和错误。
Fetch API
javascript
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) throw new Error('请求失败');
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error(error));
- 优点:
- 链式调用,逻辑清晰。
- 默认返回 Promise,支持
async/await。
3. 关键功能差异
| 功能 | Fetch | AJAX |
|---|---|---|
| 请求取消 | 通过 AbortController 实现 |
原生支持 xhr.abort() |
| 超时控制 | 需手动封装 Promise.race |
原生支持 xhr.timeout |
| 响应类型 | 需调用 .json()/.text() 等方法 |
通过 xhr.responseType 直接设置 |
| Cookie 发送 | 默认不携带,需设置 credentials: 'include' |
默认携带 |
| 进度监控 | 不支持 | 支持 xhr.upload.onprogress |
4. 实际应用场景
优先使用 Fetch 的情况
- 现代前端项目:
javascript
// 结合 async/await 更简洁 async function loadData() { try { const res = await fetch('/api/data'); const data = await res.json(); console.log(data); } catch (error) { console.error(error); } } - 需要流式数据处理:
javascript
const response = await fetch('/large-file'); const reader = response.body.getReader(); // 逐块读取数据
仍需使用 AJAX 的情况
- 兼容旧浏览器(如 IE11):
javascript
if (typeof fetch === 'undefined') { // 回退到 AJAX } - 需要上传进度监控:
javascript
xhr.upload.onprogress = (e) => { const percent = (e.loaded / e.total) * 100; console.log(`上传进度: ${percent}%`); };
5. 补充说明
- jQuery 的
$.ajax:
封装了 XMLHttpRequest,提供更简单的语法,但仍基于回调:javascript$.ajax({ url: '/api/data', method: 'GET', success: (data) => console.log(data), error: (err) => console.error(err) }); - Axios:
基于 Promise 的第三方库,兼容浏览器和 Node.js,综合了 Fetch 和 AJAX 的优点:javascriptaxios.get('/api/data') .then(response => console.log(response.data)) .catch(error => console.error(error));
总结
| 维度 | Winner | 原因 |
|---|---|---|
| 代码简洁性 | Fetch | Promise 链式调用比回调更直观 |
| 功能完整性 | AJAX | 原生支持取消、超时、进度监控等特性 |
| 现代开发 | Fetch/Axios | 原生或第三方库对 Promise 和 TypeScript 支持更好 |
建议:
- 新项目优先使用 Fetch API 或 Axios。
- 旧项目维护或需要特定功能(如上传进度)时选择 AJAX。
对于监听网络传输(如监控请求/响应进度、流量分析或调试),fetch 和 AJAX 的能力差异显著。以下是具体对比和解决方案:
1. 进度监控能力对比
| 功能 | Fetch API | AJAX (XMLHttpRequest) |
|---|---|---|
| 下载进度 | ❌ 原生不支持 | ✅ 通过 xhr.onprogress 监听 |
| 上传进度 | ❌ 原生不支持 | ✅ 通过 xhr.upload.onprogress |
| 实时中断请求 | ✅ 通过 AbortController |
✅ 原生 xhr.abort() |
| 分块数据流处理 | ✅ 支持 response.body.getReader() |
❌ 仅能获取完整响应 |
2. 监听网络传输的具体实现
(1)AJAX 的完整进度监控
javascript
const xhr = new XMLHttpRequest();
// 上传进度监听
xhr.upload.onprogress = (e) => {
const uploadPercent = Math.round((e.loaded / e.total) * 100);
console.log(`上传进度: ${uploadPercent}%`);
};
// 下载进度监听
xhr.onprogress = (e) => {
const downloadPercent = Math.round((e.loaded / e.total) * 100);
console.log(`下载进度: ${downloadPercent}%`);
};
xhr.open('POST', '/api/upload');
xhr.send(formData);
优势:
- 原生支持上传/下载进度监控,适合大文件传输场景。
(2)Fetch API 的变通方案
虽然原生 fetch 不支持进度事件,但可通过以下方式实现类似功能:
方案1:分块读取响应流(仅下载)
javascript
const response = await fetch('/api/large-file');
const reader = response.body.getReader();
let receivedLength = 0;
const totalLength = +response.headers.get('Content-Length');
while (true) {
const { done, value } = await reader.read();
if (done) break;
receivedLength += value.length;
console.log(`下载进度: ${Math.round((receivedLength / totalLength) * 100)}%`);
}
方案2:自定义包装器(上传进度需借助中间层)
javascript
async function fetchWithProgress(url, options) {
const { onUploadProgress, ...fetchOptions } = options;
// 如果是 FormData 上传,需手动计算进度(非精确)
if (onUploadProgress && fetchOptions.body instanceof FormData) {
const totalSize = [...fetchOptions.body].reduce((acc, [k, v]) =>
acc + (v instanceof File ? v.size : String(v).length), 0);
let uploaded = 0;
// 劫持 body 的流式写入
const originalBody = fetchOptions.body;
const trackedStream = new ReadableStream({
start(controller) {
const reader = originalBody.stream().getReader();
async function push() {
const { done, value } = await reader.read();
if (done) {
controller.close();
return;
}
uploaded += value.length;
onUploadProgress({ loaded: uploaded, total: totalSize });
controller.enqueue(value);
push();
}
push();
}
});
fetchOptions.body = trackedStream;
}
return fetch(url, fetchOptions);
}
// 使用示例
fetchWithProgress('/api/upload', {
method: 'POST',
body: formData,
onUploadProgress: (e) => {
console.log(`上传进度: ${Math.round((e.loaded / e.total) * 100)}%`);
}
});
局限性:
- 上传进度监控需要手动劫持数据流,且对非
FormData类型支持有限。
3. 高级网络分析工具
(1)浏览器开发者工具
- Network 面板:直接查看所有请求的耗时、流量大小和瀑布图。
- Performance 面板:分析网络请求对页面性能的影响。
(2)第三方库
- Axios:封装了上传/下载进度监听:
javascript
axios.post('/api/upload', formData, { onUploadProgress: (progressEvent) => { const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100); console.log(`上传进度: ${percent}%`); } }); - Pako:用于监控压缩流量(如 Gzip 数据流)。
(3)Service Worker 拦截
通过 Service Worker 监听所有 fetch 请求,实现流量统计或缓存控制:
javascript
// service-worker.js
self.addEventListener('fetch', (event) => {
console.log(`拦截请求: ${event.request.url}`);
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});
4. 适用场景推荐
| 需求 | 推荐方案 |
|---|---|
| 精确的上传/下载进度监控 | AJAX(xhr.upload.onprogress) |
| 流式数据处理 | Fetch API(response.body.getReader()) |
| 兼容旧浏览器 | AJAX 或 Axios |
| 全局网络拦截/分析 | Service Worker + Fetch 监听 |
总结
- AJAX 是进度监控的“原生王者”,适合文件上传等场景。
- Fetch API 更现代且支持流式处理,但需额外代码实现进度监听。
- 终极方案:优先使用
fetch+AbortController(中断请求)和ReadableStream(流处理),必要时用 Axios 或降级到 AJAX。
