你想弄清楚 Fetch 流式的核心定义、工作原理和实际价值,简单来说,Fetch 流式是 Fetch API 提供的「边接收、边处理」数据的能力,它让前端不再需要等待服务端返回完整的响应数据,而是能逐块读取、处理数据,是前端处理大文件、实时数据的核心能力之一。
一、Fetch 流式的核心定义
Fetch 流式(Fetch Streaming)是基于浏览器原生 Fetch API 实现的流式数据处理能力:
- 普通 Fetch 请求:服务端返回完整的响应数据,前端一次性接收所有数据后才能处理(比如
res.json()/res.text() 都是一次性解析);
- Fetch 流式:服务端通过 HTTP Chunked(分块传输编码)返回数据,Fetch 请求的响应体
response.body 会返回 ReadableStream(可读流)对象,前端可以逐块读取服务端发送的「数据块」,边接收、边解析、边处理,无需等待整个响应完成。
核心原理(一句话讲透)
Fetch 流式的底层是「HTTP 分块传输 + 浏览器 Streams API」的组合:
- 服务端开启 HTTP Chunked 编码,将数据切分成多个独立的「数据块」,逐个发送给前端;
- 前端 Fetch 拿到响应后,
response.body 暴露为 ReadableStream 可读流;
- 前端通过流的读取器(
reader)逐块读取这些数据,实现流式处理。
二、Fetch 流式的核心用法(极简代码示例)
Fetch 流式的核心是操作 response.body(ReadableStream),以下是最常见的 2 个场景:
场景 1:流式读取文本 / JSON 数据(比如实时日志、大模型打字机效果)
async function streamFetchText(url) {
// 1. 发起 Fetch 请求
const response = await fetch(url);
// 校验:确保响应有效且支持流式(response.body 是 ReadableStream)
if (!response.ok || !response.body) {
throw new Error("请求失败或不支持流式响应");
}
// 2. 获取流的读取器
const reader = response.body.getReader();
// 3. 二进制流转文本的解码器(关键:stream: true 保证分块解码不乱码)
const decoder = new TextDecoder("utf-8", { stream: true });
try {
// 4. 循环逐块读取数据(流式核心逻辑)
while (true) {
// done: 是否读取完成;value: 当前数据块(Uint8Array 二进制格式)
const { done, value } = await reader.read();
if (done) break; // 读取完成,退出循环
// 5. 实时处理当前数据块(比如渲染到页面、解析JSON)
const chunkText = decoder.decode(value);
console.log("实时读取的内容块:", chunkText);
// 示例:实时追加到页面(模拟大模型打字机效果)
document.getElementById("content").textContent += chunkText;
}
} finally {
// 6. 释放读取器(关键:避免内存泄漏)
reader.releaseLock();
}
}
// 调用示例(比如请求返回流式文本的接口)
streamFetchText("/api/stream-log");
async function streamDownloadFile(url, fileName) {
const response = await fetch(url);
if (!response.ok || !response.body) throw new Error("下载失败");
// 1. 将流式响应体转为 Blob(浏览器自动拼接分块数据)
const blob = await new Response(response.body).blob();
// 2. 创建下载链接并触发下载
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = fileName;
a.click();
// 3. 清理资源
URL.revokeObjectURL(downloadUrl);
}
// 调用示例(下载1GB+的大文件)
streamDownloadFile("/api/download/large-file", "超大文件.zip");