详细对比JS中XMLHttpRequest和fetch的使用

在JavaScript中,XMLHttpRequestfetch 是两种用于进行 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 提供的特定功能。

相关推荐
牛奔14 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
寻星探路17 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
lly20240619 小时前
Bootstrap 警告框
开发语言
2601_9491465320 小时前
C语言语音通知接口接入教程:如何使用C语言直接调用语音预警API
c语言·开发语言
曹牧20 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
KYGALYX20 小时前
服务异步通信
开发语言·后端·微服务·ruby
zmzb010320 小时前
C++课后习题训练记录Day98
开发语言·c++
猫头虎21 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
Moment21 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
YUJIANYUE21 小时前
PHP纹路验证码
开发语言·php