普通Fetch和Fetch 流式的区别?
<h1 data-id="heading-0">🧑💻 写在开头</h1><p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<div>
<div>
<p>你想弄清楚 Fetch 流式的核心定义、工作原理和实际价值,简单来说,<strong>Fetch 流式是 Fetch API 提供的「边接收、边处理」数据的能力</strong>,它让前端不再需要等待服务端返回完整的响应数据,而是能逐块读取、处理数据,是前端处理大文件、实时数据的核心能力之一。</p>
<hr>
<h2 data-id="heading-0">一、Fetch 流式的核心定义</h2>
<p>Fetch 流式(Fetch Streaming)是基于浏览器原生 <code>Fetch API</code> 实现的<strong>流式数据处理能力</strong>:</p>
<ul>
<li>普通 Fetch 请求:服务端返回<strong>完整的响应数据</strong>,前端一次性接收所有数据后才能处理(比如 <code>res.json()</code>/<code>res.text()</code> 都是一次性解析);</li>
<li>Fetch 流式:服务端通过 HTTP Chunked(分块传输编码)返回数据,Fetch 请求的响应体 <code>response.body</code> 会返回 <code>ReadableStream</code>(可读流)对象,前端可以<strong>逐块读取服务端发送的「数据块」</strong>,边接收、边解析、边处理,无需等待整个响应完成。</li>
</ul>
<h3 data-id="heading-1">核心原理(一句话讲透)</h3>
<p>Fetch 流式的底层是「<strong>HTTP 分块传输 + 浏览器 Streams API</strong>」的组合:</p>
<ol>
<li>服务端开启 HTTP Chunked 编码,将数据切分成多个独立的「数据块」,逐个发送给前端;</li>
<li>前端 Fetch 拿到响应后,<code>response.body</code> 暴露为 <code>ReadableStream</code> 可读流;</li>
<li>前端通过流的读取器(<code>reader</code>)逐块读取这些数据,实现流式处理。</li>
</ol>
<h2 data-id="heading-2">二、Fetch 流式的核心用法(极简代码示例)</h2>
<p>Fetch 流式的核心是操作 <code>response.body</code>(ReadableStream),以下是最常见的 2 个场景:</p>
<h3 data-id="heading-3">场景 1:流式读取文本 / JSON 数据(比如实时日志、大模型打字机效果)</h3>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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");</pre>
</div>
<h3 data-id="heading-4">场景 2:流式下载大文件(避免内存溢出)</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">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");</pre>
</div>
<div>
<div>
<h2 data-id="heading-5">三、Fetch 流式的核心使用场景</h2>
<ol>
<li><strong>大文件下载</strong>:下载 100MB+ 的文件时,流式下载仅占用少量内存,避免一次性加载导致的页面卡顿 / 内存溢出;</li>
<li><strong>实时数据接收</strong>:接收服务端推送的实时日志、后台任务进度、大模型的流式响应(打字机效果);</li>
<li><strong>超大 JSON 解析</strong>:服务端返回百万条数据的 JSON 列表时,流式逐块解析,实时渲染到页面(比如表格);</li>
<li><strong>二进制流处理</strong>:流式读取图片 / 视频等二进制文件,实时预览或处理(比如图片压缩)。</li>
</ol>
<h2 data-id="heading-6">四、Fetch 流式 vs 普通 Fetch 的核心区别</h2>
</div>
<p><img src="https://img2024.cnblogs.com/blog/2149129/202602/2149129-20260212203734467-927595455.png" alt="ScreenShot_2026-02-12_203637_684" loading="lazy"></p>
<div>
<div>
<h3 data-id="heading-7">总结</h3>
<ol>
<li><strong>核心本质</strong>:Fetch 流式是 Fetch API 结合 HTTP Chunked 分块传输,通过 <code>response.body</code>(ReadableStream)实现的逐块数据处理能力;</li>
<li><strong>核心价值</strong>:解决大文件 / 实时数据一次性加载导致的「内存溢出、页面卡顿、等待时间长」问题;</li>
<li><strong>核心用法</strong>:通过 <code>reader.read()</code> 循环读取数据块,配合 <code>TextDecoder</code> 处理文本,或直接转为 Blob 实现流式下载。</li>
</ol></div>
<div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p>
</div>
</div>
</div><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19609675
頁:
[1]