从 XMLHttpRequest 到 Fetch:我用 JS 打通了与服务器的任督二脉!

126 阅读4分钟

👋 前言:前端小白第一次“联网”的惊吓与成长

当我刚学 JavaScript 的时候,觉得网页就该“静静地美丽着”,没想到还有“和服务器说话”这种操作。

直到有一天,我点开了 Chrome 的 DevTools,刷新页面的一瞬间,看着 Network 面板蹦出一堆请求,我意识到:“原来浏览器一直在背地里‘密谋’着什么!”

于是,我开始探索:JS 是怎么跟服务器唠嗑的?
结果发现了两位老少搭档:

🧓 XMLHttpRequest:江湖人称 XHR,AJAX 之父,兢兢业业 20 年
🧒 Fetch:前端新时代的语法颜值担当,Promise 加持

今天,就让我带你从 XHR 一路走向 Fetch,了解它们之间的血泪史与技术交接。


📦 第一代通信工具:XMLHttpRequest(XHR)

🔧 基本用法(经典五步法)

const xhr = new XMLHttpRequest(); // 1. 创建对象
xhr.open('GET', 'https://api.example.com/data', true); // 2. 初始化请求
xhr.onreadystatechange = function () { // 3. 注册事件监听
  if (xhr.readyState === 4 && xhr.status === 200) { // 4. 判断状态
    console.log(xhr.responseText); // 5. 处理响应数据
  }
};
xhr.send(); // 发出请求

这段代码就像一部微型宫廷剧,从发话(open)到办事(send),再到回信(readyState),你得处处小心才能得数据。

📊 readyState 状态码

状态码含义
0请求未初始化
1请求已建立
2请求已发送
3请求处理中(部分数据)
4请求已完成,响应就绪

我们只关心 readyState === 4 && status === 200 的高光时刻。

🧪 POST 请求的写法

const xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.example.com/user', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(JSON.parse(xhr.responseText));
  }
};
xhr.send(JSON.stringify({
  name: '前端小白',
  age: 18
}));

XHR 就是这样,“多事多虑”,你必须手动设置 header、判断状态、解析响应……有种“旧时代手工艺人”的味道。


🚀 第二代新宠:Fetch API —— Promise 驱动的优雅新世界

🧼 最简洁的 GET 写法

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('出错了:', error));

你没看错,就是这么简单。没有了 readyStateonreadystatechange,返回的是 Promise,优雅得像一篇英文诗。

🧃POST 请求的写法

fetch('https://api.example.com/user', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: '掘金学徒',
    age: 20
  })
})
  .then(res => {
    if (!res.ok) throw new Error('服务器崩了!');
    return res.json();
  })
  .then(data => console.log(data))
  .catch(err => console.error(err));

Fetch 更加语义化,处理错误也更清晰。你只需专注于“我要什么”,而不是“怎么获取”。


🥊 XHR VS Fetch:来一场公平对决!

功能点XMLHttpRequestFetch
语法简洁❌ 多回调 + 状态判断✅ Promise 链式风格
默认支持 Promise
错误处理❌ 需要多层嵌套判断✅ 可用 .catch() 捕获
支持取消请求❌ 不支持✅ 支持 AbortController
自动处理 JSON❌ 手动解析✅ 自带 .json() 方法
跨域带 cookie❌ 需要复杂设置credentials: 'include'
兼容性✅ 支持 IE 等古董浏览器❌ IE 不支持

📢 总结一句话:XHR 是“手动档”,Fetch 是“自动挡”。
Fetch 写起来轻松,但也不能抛弃 XHR,因为它仍在很多老项目中坚守岗位。


🧰 小工具:封装一个简单的 fetch 请求器

如果你想自己动手封装一个 fetch 工具,下面是个超基础版本:

function request(url, options = {}) {
  return fetch(url, {
    method: options.method || 'GET',
    headers: {
      'Content-Type': 'application/json',
      ...(options.headers || {})
    },
    body: options.body ? JSON.stringify(options.body) : null
  })
    .then(res => {
      if (!res.ok) throw new Error(res.statusText);
      return res.json();
    });
}

使用方法:

request('https://api.example.com/data')
  .then(data => console.log(data))
  .catch(err => console.error(err));

更进一步,你可以引入 try...catch + async/await 写法,像这样:

async function getData() {
  try {
    const res = await fetch('https://api.example.com/data');
    if (!res.ok) throw new Error('网络不稳定');
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error('请求失败:', err);
  }
}

🧠 面试官可能问的问题

  1. XHR 和 Fetch 的区别?

    • 回调 vs Promise
    • 状态判断复杂 vs 简洁
    • 错误处理 vs 明确抛错
  2. fetch 为什么不能直接取消请求?

    • 需要借助 AbortController

      const controller = new AbortController();
      fetch(url, { signal: controller.signal });
      controller.abort(); // 中止请求
      
  3. fetch 默认不带 cookie 怎么解决?

    • 设置 credentials: 'include'

📌 总结:从 XHR 到 Fetch,别只是抄 API,要理解通信的本质!

XHR 是网络通信的老牌工具,适合理解底层原理
Fetch 是现代前端的标配,配合 async/await 简直爽飞
理解状态码、异步处理、错误捕获,是面试和项目的必备技能
不管你用啥工具,请永远记得:网络通信 = 发请求 + 等响应 + 处理异常


💬 最后一口鸡汤:技术不是堆 API,是对“流程”的掌控

XHR 是老师,Fetch 是朋友。
学会了它们,你就不再是那个只会 alert('你好') 的 JS 小白了。

未来你还会遇到 Axios、GraphQL、WebSocket……
但你得先迈过这第一步,才能走进前端通信的“高级殿堂”。


如果你觉得这篇文章帮你打开了 JS 的“网络之眼”,欢迎点赞、评论、收藏~
如果你还想看我写“从 Fetch 到 Axios 的三国演义”,评论区见!