一文搞懂 Fetch API

484 阅读5分钟

本文大部分内容由AI生成,笔记类整合记录;

Fetch API 是现代浏览器提供的一个用于发起网络请求的 JavaScript 接口,它提供了一种更强大、更灵活的方式来处理 HTTP 请求,替代了传统的 XMLHttpRequest (XHR)。

Fetch API 提供了一个全局的 fetch() 方法,该方法返回一个 Promise 对象,用于获取网络资源。它的设计遵循"请求-响应"模型,使得处理异步网络请求更加简洁明了

核心组成部分:Request、Response、Headers

使用示例:

// GET
fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('There was a problem with the fetch operation:', error);
  });
​
​
// POST
fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'John Doe',
    age: 30
  })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

高级特性:

  • 取消 Fetch 请求

  • 上传文件

  • 流式处理响应

  • 错误处理

    Fetch 只在网络错误时 reject Promise,HTTP 错误状态 (如 404 或 500) 不会导致 reject。因此需要检查 response.okresponse.status

对比 XML

特性Fetch APIXMLHttpRequest
语法基于 Promise,更简洁回调方式,较复杂
流式处理支持不支持
请求取消通过 AbortController原生支持
响应类型多种转换方法需要手动设置
CORS 处理更简单较复杂
进度事件不支持支持
浏览器支持现代浏览器所有浏览器
请求头操作Headers 对象直接设置

问题:

1、它是什么时候出来的?

Fetch API 是在2015年正式成为Web标准的,具体时间线如下:

  • 2011年:最初由GitHub团队提出概念
  • 2014年:开始被主流浏览器实现
  • 2015年:正式成为WHATWG标准的一部分
  • 2016年:被纳入W3C标准

2、它为什么出来,有什么优势?

  • 基于Promise的简洁语法

  • 更合理的默认行为

    • 不会将HTTP错误状态(如404/500)视为网络错误(XHR会触发onerror)
    • 自动处理CORS相关头部
    • 更简单的请求/响应抽象
  • 更现代的API设计

  • 流式数据处理能力

  • 更好的头信息管理

  • 更灵活的配置选项

3、它的缺陷

尽管Fetch API有很多优势,但也存在一些限制:

  1. 没有原生进度事件:上传/下载进度需要额外实现
  2. IE完全不支持:必须使用polyfill
  3. 默认不发送/接收cookie:需要显式设置credentials
  4. HTTP错误不会reject:需要手动检查response.ok
  5. 较新的高级功能:如流式处理在某些浏览器支持不完整

4、日常开发中,我们应该如何选择?

在日常前端开发中,选择使用原生 Fetch API 还是 Axios 是一个常见的决策点。下面我将详细分析如何选择。

选择标准对比表:

标准Fetch APIAxios
浏览器兼容性现代浏览器(需polyfill支持IE)全浏览器支持(包括IE)
语法简洁性较简洁更简洁(特别是拦截器、取消等)
功能完整性基础功能全面功能(进度、取消、拦截器等)
错误处理需手动检查HTTP错误自动处理HTTP错误
请求/响应转换需手动处理自动转换JSON数据
超时控制需结合AbortController实现内置支持
CSRF防护需手动实现内置支持
上传进度不支持支持
体积原生API(0kb)约4kb(压缩后)

具体选择建议

  1. 推荐使用 Fetch 的场景

    • 开发PWA或需要最小化依赖的项目
    • 只需要基础网络请求功能
    • 目标平台是现代浏览器(或已配置polyfill)
    • 项目对包体积极度敏感
  2. 推荐使用 Axios 的场景

    • 需要支持旧版浏览器(如IE11)
    • 项目需要请求/响应拦截器
    • 需要上传/下载进度跟踪
    • 需要更简洁的错误处理
    • 需要自动JSON转换
    • 项目已使用Axios且无迁移必要
  3. 现代替代方案考虑

    • 如果使用React:可考虑React Query或SWR
    • 如果使用Vue:可考虑VueRequest
    • 如果追求极致轻量:可考虑redaxios(类似Axios API的1kb替代)

5、fetch 为什么需要两次await 才能拿到数据?

Fetch API 设计中使用两次 await 的原因涉及响应处理流程的分阶段特性。

核心原因:分阶段响应处理

Fetch 将 HTTP 请求/响应过程明确分为两个阶段:

  1. 元数据获取阶段(第一个 await),理解为获取Header内容

    • 获取响应状态、头部等元数据
    • 验证响应是否成功(检查 response.ok
  2. 正文内容获取阶段(第二个 await),获取Body内容,次过程是一个异步状态

    • 实际读取响应体内容
    • 将原始数据转换为所需格式(JSON/text/blob 等)

详细流程解析

1. 第一次 await:获取 Response 对象

javascript

const response = await fetch(url);

这行代码完成后你得到的是:

  • HTTP 状态码(response.status
  • 响应头(response.headers
  • 响应是否成功的标志(response.ok
  • 一个未读取的响应体流response.body

此时响应体尚未被读取,因为:

  1. 性能优化:避免立即读取可能不需要的大响应体
  2. 灵活性:允许开发者先检查元数据再决定如何处理响应体
2. 第二次 await:获取响应体内容

javascript

const data = await response.json();

这个阶段实际完成:

  1. 从网络流中读取原始响应数据
  2. 将数据解析为指定格式(这里是JSON)
  3. 返回解析后的结果

总结:

这样设计的目的:

  • 明确的流程控制:清晰分离元数据和内容处理
  • 性能优化:支持流式处理和延迟加载
  • 灵活性:允许开发者根据响应状态决定处理方式