文章目录

JavaScript AJAX:XMLHttpRequest 与 fetch API

发布于 2026-04-11 02:24:59 · 浏览 7 次 · 评论 0 条

JavaScript AJAX:XMLHttpRequest 与 fetch API

AJAX(Asynchronous JavaScript and XML)允许网页在不重新加载整个页面的情况下,与服务器交换数据并更新部分内容。这是现代 Web 应用交互的核心。目前,实现 AJAX 主要有两种方式:传统的 XMLHttpRequest (XHR) 和现代的 fetch API。


一、 XMLHttpRequest (XHR):传统的基石

XMLHttpRequest 是实现 AJAX 的原始技术。尽管它名称中包含 XML,但它可以获取任何类型的数据。虽然代码写起来相对繁琐,但它在所有旧版浏览器中都有极好的兼容性。

使用 XHR 获取数据通常包含以下步骤:

  1. 创建 一个 XMLHttpRequest 对象。
  2. 配置 请求参数(如方法、URL)。
  3. 监听 状态变化事件。
  4. 发送 请求。

具体代码实现如下:

// 1. 创建对象
const xhr = new XMLHttpRequest();

// 2. 监听状态变化
// readyState: 0=未初始化, 1=载入中, 2=载入完成, 3=解析中, 4=完成
xhr.onreadystatechange = function() {
  // 检查请求是否完成 (readyState 4) 且成功 (status 200)
  if (xhr.readyState === 4 && xhr.status === 200) {
    // 5. 处理返回的数据
    console.log(xhr.responseText);
  }
};

// 3. 配置请求:GET 方法,目标 URL,异步执行
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1', true);

// 4. 发送请求
xhr.send();

二、 fetch API:现代的标准

fetch 是基于 Promise 设计的 API,旨在取代 XMLHttpRequest。它语法更简洁,逻辑更清晰,且原生支持流式处理。fetch 返回一个 Promise 对象,这使得链式调用和 async/await 语法变得非常容易。

使用 fetch 获取数据通常包含以下步骤:

  1. 调用 fetch() 函数并传入 URL。
  2. 使用 .then()await 处理返回的 Promise。
  3. 解析 响应体(如 .json())。
  4. 处理 最终数据。

具体代码实现如下:

// 使用 Promise 链式调用
fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => {
    // 检查网络请求是否成功
    if (!response.ok) {
      throw new Error('网络响应异常');
    }
    // 解析 JSON 数据
    return response.json();
  })
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('请求失败:', error);
  });

推荐使用 async/await 语法,因为它更接近同步代码的逻辑,可读性更高:

async function getData() {
  try {
    // 1. 发起请求并等待响应
    const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');

    // 2. 检查 HTTP 状态码
    if (!response.ok) {
      throw new Error(`HTTP 错误! 状态: ${response.status}`);
    }

    // 3. 解析 JSON 数据
    const data = await response.json();

    // 4. 使用数据
    console.log(data);
  } catch (error) {
    console.error('获取数据出错:', error);
  }
}

getData();
```

---

### 三、 核心差异对比

理解两者的区别有助于在不同的项目场景中做出正确选择。

| 特性 | XMLHttpRequest (XHR) | fetch API |
| :--- | :--- | :--- |
| **语法风格** | 回调函数,容易产生“回调地狱” | Promise / async-await,代码扁平清晰 |
| **浏览器支持** | 支持所有旧版浏览器 (IE7+) | 现代浏览器 (IE 不支持,需 Polyfill) |
| **JSON 处理** | 需手动 `JSON.parse()` | 内置 `.json()` 方法,自动解析 |
| **错误处理** | 需结合 `onerror` 和 `status` 判断 | 网络错误走 `catch`,HTTP 错误 (如 404) 需手动检查 `response.ok` |
| **底层控制** | 控制力强,可监听上传/下载进度 | 基础版本不直接支持进度监听 (需使用 Response.body) |

**关于 XHR 进度监听的补充说明:**

如果你需要监听文件上传的进度条,`XMLHttpRequest` 提供了 `upload.onprogress` 事件,这在使用 `fetch` 时较难直接实现。

```javascript
xhr.upload.onprogress = function(event) {
  if (event.lengthComputable) {
    const percentComplete = (event.loaded / event.total) * 100;
    console.log('上传进度: ' + percentComplete + '%');
  }
};
```

---

### 四、 fetch 的常见陷阱与应对

在使用 `fetch` 时,最大的误区是认为只要 `catch` 到了错误就代表请求完全失败了。

**关键点:** 只有网络错误(如断网、DNS 解析失败)才会触发 `Promise.reject` 进入 `catch`。如果服务器返回了 HTTP 状态码(如 `404 Not Found` 或 `500 Server Error`),`fetch` 会认为请求“成功”完成(因为 TCP 握手成功了),从而进入 `then` 分支。

因此,**务必检查** `response.ok` 属性或 `response.status`。

**错误的写法(可能吞掉 404/500 错误):**

```javascript
fetch('/api/wrong-url')
  .then(response => response.json()) // 404 页面可能不是合法 JSON,这里可能会报错
  .catch(error => console.log(error)); // 仅捕获网络错误
```

**正确的写法:**

```javascript
fetch('/api/wrong-url')
  .then(response => {
    if (!response.ok) {
      // 手动抛出错误,使其进入 catch
      throw new Error(`状态码 ${response.status}`);
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('请求或处理出错:', error));

五、 请求流程解析

为了更直观地理解 fetch 处理请求和响应的完整逻辑,以下是标准的异步数据获取流程图:

graph TD A["Start: Call fetch url"] --> B{Network OK?} B -- "No (Offline)" --> C["Catch Error"] C --> F["End"] B -- "Yes" --> D["Receive Response Object"] D --> E{"HTTP Status OK? (200-299)"} E -- "No (e.g. 404, 500)" --> G["Throw Error manually"] G --> C E -- "Yes" --> H["Parse Data: response.json"] H --> I["Use Data in Logic"] I --> F

六、 实际应用建议

在以下情况使用 fetch

  • 项目主要针对现代浏览器或移动端 Web 应用。
  • 代码结构需要简洁,大量使用了 async/await
  • 需要处理流式数据。

在以下情况使用 XMLHttpRequest

  • 需要支持 Internet Explorer 等老旧浏览器。
  • 需要精确监听上传或下载的进度事件。
  • 需要同步请求(虽然极度不推荐,但在极少数特定场景下 XHR 支持同步模式)。

总结用法示例(POST 请求):

在使用 fetch 发送 POST 请求时,必须设置请求头并序列化请求体。

async function postData() {
  const url = 'https://jsonplaceholder.typicode.com/posts';
  const data = { title: 'foo', body: 'bar', userId: 1 };

  try {
    const response = await fetch(url, {
      method: 'POST', // 指定方法
      headers: {
        'Content-Type': 'application/json' // 声明发送的数据类型
      },
      body: JSON.stringify(data) // 将对象转换为 JSON 字符串
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const responseData = await response.json();
    console.log('服务器返回:', responseData);
  } catch (error) {
    console.error('发送失败:', error);
  }
}

postData();

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文