首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >浏览器里的"流"到底是什么?把它想成小区的自来水净化站

浏览器里的"流"到底是什么?把它想成小区的自来水净化站

作者头像
前端达人
发布2026-07-10 21:43:44
发布2026-07-10 21:43:44
790
举报
文章被收录于专栏:前端达人前端达人

一句话说清楚:以前处理大文件、大数据,都得先把"一整桶水"倒进内存这个大缸里,等倒满了才能处理;而"流"(Stream)让数据像自来水一样,边流边处理,压根不用等整缸水都到齐。

打个比方:把这套东西想成小区自来水净化站

小区里的自来水,不是先把一个水库的水全部抽到你家,再让你慢慢处理,而是水源接了一根管子,中间串了好几道处理站——过滤站、消毒站、加压站,水一路流过去,边流边处理,最后从水龙头流出来就是能直接喝的水。

浏览器里的"流处理"就是这个思路:数据像水一样,从"进水口"流入,经过几道"处理站"(这就是 TransformStream),最后流到"出水口"(存文件、传网络、显示在页面上)。整个过程不需要先把全部数据攒在内存里,处理超大文件、实时数据的时候,内存不会被撑爆,用户也不用干等着"缓冲进度条"转半天。

带着这根"水管"的画面,我们把 6 个常见的流技术挨个讲清楚。

处理站本体:TransformStream 就是那道"过滤网"

代码语言:javascript
复制
// 把 CSV 格式的水,净化成 JSON 格式的水
const csvToJson = new TransformStream({
  transform(chunk, controller) {
    try {
      const rows = chunk.split('\n');
      const json = rows.map(row => {
        const [name, age] = row.split(',');
        return { name, age: parseInt(age, 10) };
      });
      controller.enqueue(json); // 处理完一小段,立刻放行到下一站
    } catch (error) {
      controller.error(`CSV 解析失败:${error.message}`); // 这一小段水质有问题,报警
    }
  }
});

transform() 这个方法就是过滤网本身——水流过来一小段(一个 chunk),它就地处理一下,处理完立刻 enqueue 放行到下一道工序,不用等"一整桶水"都到齐才开始干活。

业务场景很实在:假设你要把一个几个 GB 的传感器日志文件,从 CSV 转成 JSON 存进数据库。要是老老实实"整桶端进来再处理",浏览器内存分分钟爆掉;换成流处理,数据一边流一边转换,哪怕文件有 10 个 G,浏览器也不会卡死——原理就是自来水站从不会因为水库水多就把水管撑爆,因为水从来都是一小段一小段过去的。

接水管的第一步:Blob 直接变成一根"水管"

代码语言:javascript
复制
document.querySelector('input[type=file]').addEventListener('change', async (e) => {
  const blobStream = e.target.files[0].stream(); // 文件秒变一根水管
  const processed = blobStream.pipeThrough(new VideoCompressor()); // 接上"压缩处理站"
  await processed.pipeTo(uploadToServer()); // 边压缩边传,不用等压完再传
});

以前处理用户上传的文件,习惯是"先把整个文件读进内存变成一大坨数据,再开始处理"——这就好比先把一整桶水倒进自己家水缸,再从缸里舀水处理,多此一举。

file.stream() 干的事,就是直接把这个文件"接成一根水管",不用先倒进缸里。业务场景:用户上传一个几百 MB 的视频,你想边上传边压缩边转码,pipeThrough 就是往这根水管上串联处理站,pipeTo 就是接到最终出口(服务器),全程没有"先囤积、再处理"这一步,用户体验自然快很多。

水质检测站:文字编码解码流

代码语言:javascript
复制
// 一个实时翻译流水线:原始二进制 → 西班牙语文字 → 翻译 → 英文文字 → 二进制存盘
fetch('/api/spanish-text')
  .then(response =>
    response.body
      .pipeThrough(new TextDecoderStream())  // 二进制水 → 文字水
      .pipeThrough(translateToEnglish)        // 翻译处理站(自定义的过滤网)
      .pipeThrough(new TextEncoderStream())   // 文字水 → 二进制水,方便存盘
      .pipeTo(saveFileStream)
  );

网络里传的数据本质上都是二进制"原水",人看不懂。TextDecoderStream 就像水质检测站,自动把这些看不懂的原始信号翻译成人类能读的文字;处理完之后如果还要存盘或者再传输,TextEncoderStream 再把文字重新编码回二进制。

业务场景:做一个多语言客服系统,后端不断吐出西班牙语的对话记录,你要一边接收一边实时翻译成中文展示给客服人员看——用这套流水线,数据到一句、翻一句、显示一句,不用等整段对话说完才开始处理,用户体验就是"实时同传"的感觉。

浓缩站:CompressionStream 边流边挤水分

代码语言:javascript
复制
const uploadCompressed = async (file) => {
  const readable = file.stream();
  const compressed = readable.pipeThrough(new CompressionStream('gzip')); // 边流边压缩
  await fetch('/upload', {
    method: 'POST',
    body: compressed,
    headers: { 'Content-Encoding': 'gzip' }
  });
};

CompressionStream 想成净水站里的"浓缩工序"——水还在管子里流着的时候,就顺手把多余的水分挤掉,体积变小了再往下游送,到了目的地再还原回来就行。

业务场景很直接:公司 APP 的安装包有 200MB,用户上传或者下发更新包的时候,边传边压缩,实测能把体积压掉 78%——这意味着服务器带宽成本直接砍掉大头,用户下载也更快。以前得先把文件整个压缩好、生成一个新文件,再上传,现在这两步在水管里一次性搞定。

双向水管带阀门:WebSocketStream

代码语言:javascript
复制
const wss = new WebSocketStream('wss://stock-prices');
const { readable, writable } = await wss.connection;

// 只放行超过预警线的报价,别把界面刷爆
readable.pipeThrough(new TransformStream({
  transform(quote, controller) {
    if (quote.price > alertThreshold) controller.enqueue(quote);
  }
})).pipeTo(updateDashboard);

普通的 WebSocket 用起来,很容易出现"消息堆积"的问题——服务器狂推消息,前端处理不过来,全堆在内存里,界面越来越卡。WebSocketStream 相当于这根水管自带一个智能阀门:下游(界面渲染)处理不过来的时候,阀门会自动调小上游的流速,不会因为你家水龙头开得太小,把整根水管憋炸——这就是"背压"(backpressure)机制。

业务场景:做一个实时股票行情看板,服务器每秒推几十条报价,你只想展示"超过预警线"的那几条。用上面这段代码,处理站(TransformStream)先做一道筛选,只放行需要关注的数据,界面渲染压力小了很多。用完记得调用 releaseLock() 把水管松开,不然这根管子会一直占着资源不释放,时间长了就是内存泄漏。

接到硬件水龙头:SerialPort 流

代码语言:javascript
复制
const port = await navigator.serial.requestPort(); // 找到那个硬件"水龙头"
await port.open({ baudRate: 9600 });

// 一滴一滴读传感器的数据
const reader = port.readable.getReader();
while (true) {
  const { value } = await reader.read();
  console.log('传感器读数:', value);
}

这是最容易被忽略的一种"水管"——它接的不是文件也不是网络请求,而是实打实的硬件设备,比如通过 USB 连着的 Arduino 传感器。浏览器直接向硬件"打开水龙头",一滴一滴地把数据读出来。

业务场景:做智能硬件或者物联网相关的项目,比如一个温湿度监测面板,传感器每秒吐一条数据,中间数据难免有噪声干扰。这时候完全可以把 TransformStream 接到这根硬件水管上,边读边过滤掉异常值,展示给用户的永远是干净的数据。

一句话收尾

这 6 种"流"说到底都是同一个思路的不同应用场景:数据不是先囤积起来再处理,而是边流边处理,就像小区自来水从不会等水库存满才供水一样。以后再看到 pipeThroughpipeTo 这些方法,直接脑补成"往水管上再接一道处理站",ReadableStreamWritableStream 这些概念立刻就不抽象了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 打个比方:把这套东西想成小区自来水净化站
  • 处理站本体:TransformStream 就是那道"过滤网"
  • 接水管的第一步:Blob 直接变成一根"水管"
  • 水质检测站:文字编码解码流
  • 浓缩站:CompressionStream 边流边挤水分
  • 双向水管带阀门:WebSocketStream
  • 接到硬件水龙头:SerialPort 流
  • 一句话收尾
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档