在JavaScript中,XMLHttpRequest
和 fetch
是两种用于进行 HTTP 请求的 API。它们的主要区别在于设计理念、用法和功能支持。以下是两者的详细对比:
1. 语法与用法
-
XMLHttpRequest:
- 较老的 API,最早出现在 2000 年代。
- 支持异步和同步请求,但语法较为复杂。
- 使用回调函数来处理异步结果。
-
fetch:
- 于 ES6 引入,是现代浏览器提供的全新 API。
- 基于 Promise,语法更简洁且更符合异步处理的标准(async/await)。
- 更适合链式操作和流式处理。
2. 特点对比
特性 | XMLHttpRequest | fetch |
---|---|---|
支持的规范 | 基于 XMLHttpRequest 规范 | 基于 Fetch API 规范 |
异步编程 | 回调函数 | Promise / async-await |
流式响应处理 | 不支持 | 支持,通过 response.body |
跨域支持(CORS) | 需要设置额外头信息 | 默认支持 |
进度事件(onprogress) | 支持 | 不直接支持 |
请求取消 | 通过 abort() 实现 | 通过 AbortController 实现 |
错误处理 | 错误不直接抛出(需手动检查状态码) | 自动抛出网络级错误 |
文件上传 | 支持(FormData) | 支持(FormData) |
3. 代码对比
(1)XMLHttpRequest 示例
javascript">function getDataWithXHR(url) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest();xhr.open("GET", url, true); // 异步请求xhr.onreadystatechange = function () {if (xhr.readyState === 4) { // 请求完成if (xhr.status >= 200 && xhr.status < 300) {resolve(xhr.responseText); // 返回数据} else {reject(new Error(`Error: ${xhr.status}`));}}};xhr.onerror = function () {reject(new Error("Network Error"));};xhr.send();});
}// 使用
getDataWithXHR("https://jsonplaceholder.typicode.com/posts/1").then(data => console.log(data)).catch(error => console.error(error));
(2)fetch 示例
javascript">async function getDataWithFetch(url) {try {const response = await fetch(url);if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}const data = await response.json(); // 解析 JSON 数据console.log(data);} catch (error) {console.error(error);}
}// 使用
getDataWithFetch("https://jsonplaceholder.typicode.com/posts/1");
4. 功能对比
(1)进度事件支持
- XMLHttpRequest 支持通过
onprogress
事件监听下载进度:
javascript">const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts", true);
xhr.onprogress = function (event) {console.log(`Loaded ${event.loaded} of ${event.total}`);
};
xhr.onload = function () {console.log(xhr.responseText);
};
xhr.send();
- fetch 没有内置支持,需要结合
ReadableStream
实现:
javascript">async function fetchWithProgress(url) {const response = await fetch(url);const reader = response.body.getReader();const contentLength = response.headers.get("Content-Length");let receivedLength = 0;const chunks = [];while (true) {const { done, value } = await reader.read();if (done) break;chunks.push(value);receivedLength += value.length;console.log(`Received ${receivedLength} of ${contentLength}`);}const decoder = new TextDecoder("utf-8");const fullText = decoder.decode(new Blob(chunks));console.log(fullText);
}fetchWithProgress("https://jsonplaceholder.typicode.com/posts");
5. 请求取消
- XMLHttpRequest 使用
abort()
方法:
javascript">const xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts");
xhr.send();setTimeout(() => {xhr.abort();console.log("Request canceled");
}, 1000);
- fetch 使用
AbortController
:
javascript">const controller = new AbortController();
const signal = controller.signal;fetch("https://jsonplaceholder.typicode.com/posts", { signal }).then(response => response.json()).then(data => console.log(data)).catch(error => {if (error.name === "AbortError") {console.log("Request canceled");} else {console.error(error);}});// 取消请求
setTimeout(() => controller.abort(), 1000);
6. 总结
-
选择
XMLHttpRequest
的场景:- 需要兼容非常旧的浏览器。
- 需要监听进度事件。
-
选择
fetch
的场景:- 开发现代 Web 应用。
- 需要更简单的语法和更强的功能(如流式处理)。
现代开发中,推荐优先使用 fetch
,除非你需要使用 XMLHttpRequest
提供的特定功能。