本文大部分内容由AI生成,笔记类整合记录;
Fetch API 是现代浏览器提供的一个用于发起网络请求的 JavaScript 接口,它提供了一种更强大、更灵活的方式来处理 HTTP 请求,替代了传统的 XMLHttpRequest (XHR)。
Fetch API 提供了一个全局的 fetch()
方法,该方法返回一个 Promise 对象,用于获取网络资源。它的设计遵循"请求-响应"模型,使得处理异步网络请求更加简洁明了
核心组成部分:Request、Response、Headers
使用示例:
javascript
// 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.ok
或response.status
对比 XML
特性 | Fetch API | XMLHttpRequest |
---|---|---|
语法 | 基于 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有很多优势,但也存在一些限制:
- 没有原生进度事件:上传/下载进度需要额外实现
- IE完全不支持:必须使用polyfill
- 默认不发送/接收cookie:需要显式设置credentials
- HTTP错误不会reject:需要手动检查response.ok
- 较新的高级功能:如流式处理在某些浏览器支持不完整
4、日常开发中,我们应该如何选择?
在日常前端开发中,选择使用原生 Fetch API 还是 Axios 是一个常见的决策点。下面我将详细分析如何选择,并揭示 Axios 的内部实现技术。
选择标准对比表:
标准 | Fetch API | Axios |
---|---|---|
浏览器兼容性 | 现代浏览器(需polyfill支持IE) | 全浏览器支持(包括IE) |
语法简洁性 | 较简洁 | 更简洁(特别是拦截器、取消等) |
功能完整性 | 基础功能 | 全面功能(进度、取消、拦截器等) |
错误处理 | 需手动检查HTTP错误 | 自动处理HTTP错误 |
请求/响应转换 | 需手动处理 | 自动转换JSON数据 |
超时控制 | 需结合AbortController实现 | 内置支持 |
CSRF防护 | 需手动实现 | 内置支持 |
上传进度 | 不支持 | 支持 |
体积 | 原生API(0kb) | 约4kb(压缩后) |
具体选择建议
-
推荐使用 Fetch 的场景:
- 开发PWA或需要最小化依赖的项目
- 只需要基础网络请求功能
- 目标平台是现代浏览器(或已配置polyfill)
- 项目对包体积极度敏感
-
推荐使用 Axios 的场景:
- 需要支持旧版浏览器(如IE11)
- 项目需要请求/响应拦截器
- 需要上传/下载进度跟踪
- 需要更简洁的错误处理
- 需要自动JSON转换
- 项目已使用Axios且无迁移必要
-
现代替代方案考虑:
- 如果使用React:可考虑React Query或SWR
- 如果使用Vue:可考虑VueRequest
- 如果追求极致轻量:可考虑redaxios(类似Axios API的1kb替代)
5、fetch 为什么需要两次await 才能拿到数据?
Fetch API 设计中使用两次 await 的原因涉及响应处理流程的分阶段特性。
核心原因:分阶段响应处理
Fetch 将 HTTP 请求/响应过程明确分为两个阶段:
-
元数据获取阶段(第一个 await),理解为获取Header内容
- 获取响应状态、头部等元数据
- 验证响应是否成功(检查
response.ok
)
-
正文内容获取阶段(第二个 await),获取Body内容,次过程是一个异步状态
- 实际读取响应体内容
- 将原始数据转换为所需格式(JSON/text/blob 等)
详细流程解析
1. 第一次 await:获取 Response 对象
javascript
ini
const response = await fetch(url);
这行代码完成后你得到的是:
- HTTP 状态码(
response.status
) - 响应头(
response.headers
) - 响应是否成功的标志(
response.ok
) - 一个未读取的响应体流 (
response.body
)
此时响应体尚未被读取,因为:
- 性能优化:避免立即读取可能不需要的大响应体
- 灵活性:允许开发者先检查元数据再决定如何处理响应体
2. 第二次 await:获取响应体内容
javascript
ini
const data = await response.json();
这个阶段实际完成:
- 从网络流中读取原始响应数据
- 将数据解析为指定格式(这里是JSON)
- 返回解析后的结果
总结:
这样设计的目的:
- 明确的流程控制:清晰分离元数据和内容处理
- 性能优化:支持流式处理和延迟加载
- 灵活性:允许开发者根据响应状态决定处理方式