从小水管到洪流:你真的会用前端 Stream API 吗?

4 阅读2分钟

🚰 从小水管到洪流:你真的会用前端 Stream API 吗?

🧠 想象一下:处理 1G 的数据,你还在等它全加载完才开始处理?Stream API 早就能边读边处理,边下边播,效率飞起。


🎬 引子:什么是 Stream?

Stream(流)是指“按块”处理数据的一种方式,而不是等待整个数据加载完成。

在前端中,这个概念越来越重要:

  • 🚀 文件上传、下载
  • 🎥 视频边下边播
  • 📦 大型 JSON 文件解析
  • 🧠 AI 接口的流式响应(如 OpenAI)

Stream 就像一个数据的水管:一边输入(ReadableStream),一边输出(WritableStream)。


🧩 Stream API 在浏览器中的核心概念

浏览器中的 Stream API 来自 WHATWG Streams 标准,核心是三个对象:

类型作用
ReadableStream数据源,比如 fetch 响应
WritableStream数据目标,比如写入文件或 UI
TransformStream中间转换处理,比如解压或转码

🧪 实战:用 Stream 边下载边解析一个超大 JSON 文件

💡 场景:你有一个非常大的 JSON 文件(100MB+),直接 response.json() 会内存爆炸。我们可以使用 Stream 一边读取、一边解析。

📦 假设服务返回的是这样的内容:

[{"id":1,"name":"Alice"}, {"id":2,"name":"Bob"}, ...]

我们要实现:

✅ 不一次性加载内存 ✅ 逐个 item 实时处理(例如渲染 UI)


🧰 代码实战:

async function streamJsonArray(url) {
  const response = await fetch(url);
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  
  let buffer = '';
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });

    let boundary = buffer.lastIndexOf('}');
    if (boundary !== -1) {
      const chunk = buffer.slice(0, boundary + 1);
      buffer = buffer.slice(boundary + 1);

      // 处理 JSON 对象片段
      chunk.split('},').forEach(item => {
        try {
          const json = JSON.parse(item.endsWith('}') ? item : item + '}');
          console.log('Parsed Item:', json);
        } catch (e) {
          // 可能是尾巴不完整,跳过
        }
      });
    }
  }

  console.log('Stream parsing completed');
}

🔍 小技巧:

  • 使用 TextDecoder 是关键,避免二进制乱码;
  • 处理 JSON 数组需要按 } 拆分并修正;
  • 这就是典型的“边下载边处理”流式思维!

🌊 其他 Stream 的高级用法一览

📁 文件上传(ReadableStream → fetch)

const fileStream = file.stream(); // File → ReadableStream
fetch('/upload', {
  method: 'POST',
  body: fileStream
});

🎧 OpenAI API 接口流式响应处理

const response = await fetch('/ai-stream');
const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = decoder.decode(value);
  console.log('AI says:', chunk);
}

🎥 视频边播边缓存(Service Worker + Stream)

在 Service Worker 中劫持 fetch 请求,将视频数据流写入缓存。


🛠️ 浏览器原生支持情况

浏览器ReadableStreamWritableStreamTransformStream
Chrome
Edge
Firefox
Safari✅(较新版本)✅(较新版本)

🧠 总结:为什么前端要重视 Stream?

  • 📉 降低内存消耗,提升用户体验
  • ⏱️ 加快处理速度,尤其在网络/文件传输中
  • 🧬 适配未来数据流趋势(AI、大文件、直播、微服务)

Stream 不只是后端的玩具,前端也该用起来!

👍 如果你觉得这篇文章有帮助,欢迎点赞、关注、收藏,后续我会努力更新更多的javascript的实用技巧。