Streams 流处理

〇、相关 Blogs

https://juejin.cn/post/6960629859827580965?searchId=202408140740572BA1324EA3445548BFDB

一、概述

1、概览

以前,如果要处理某种资源(视频或文本文件等),必须下载整个文件,等待将其反序列化为合适的格式然后进行处理。随着 JavaScript 可以使用流,这一切都发生了变化。现在,原始数据一旦可用,就可以使用 JavaScript 进行逐步处理,而不需要生成 buffer、string 或 blob

应用:

  • 视频特效:

    用管道(pipe)把一个可读的视频流连接到一个可以添加实时特效的转换流

  • 数据解压/加压缩

    用管道把一个文件流连接到一个可以有选择地(解)压缩的转换流

  • 图片解码:

    用管道把一个HTTP响应流连接到一个可以将字节解码为位图数据的转换流,然后在连接到一个可以将位图转换为PNG转换流。如果是安装在service worker的“fetch”中,这允许你透明地填充新的图像格式,如AVIF

2、一些名词

  • Chunks

    Chunks 是写入流或从流中读取的单个数据。它可以是任何类型;流甚至可以包含很多不同类型的Chunk。大多数情况下,对一个流,chunk不是最原子的数据单元。例如,字节流可能包含由16 KiBUint8Array单元组成的块,而不是单个字节。

  • 可读流

    可读流表示一个可以从中读取的数据源。换句话说,数据来自可读流。具体地说,可读流是ReadableStream类的实例。

  • 转换流

    转换流由一对流组成:可写流(称为其可写端)和可读流(称为其可读端)。一个真实的比喻是,一个即时从一种语言翻译到另一种语言的同声传译员。对于转换流来说就是,向可写侧写入导致新数据可用于从可读侧读取。具体地说,任何具有可写属性和可读属性的对象都可以用作转换流。然而,标准的TransformStream类使得创建这样一对象变得更容易。

  • 管道链(Pipe chains)

    流主要通过管道相互连接来使用。可读流可以使用其pipeTo()方法直接通过管道传输到可写流,也可以使用可读流的pipeThrough()方法通过一个或多个转换流进行管道传输。以这种方式连接在一起的一组流称为管道链。

  • 背压(Backpressure)

    一旦一个管道链被构建,它将传播关于Chunks应该以多快的速度流过的信号。如果链中的任何一步还不能接收块,它就会通过管道链向后传播一个信号,直到最终原始源被告知停止这么快地生成chunks。 这种normalizing flow的过程称为背压。

  • Teeing

    可读流可以使用tee()方法进行tee操作(以大写“T”的形状命名,一个入口两个出口)。这将锁定流,使其不再直接可用;但是,它将创建两个新流,称为分支,可以独立使用。Teeing 也很重要,因为流不能倒带或重新启动,稍后将详细介绍。

https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a1ef3c5c7a8a403baa7c453419dd7937~tplv-k3u1fbpfcp-zoom-in-crop-mark:1512:0:0:0.awebp

可读流的机制 #
一个可读流是一个数据源,在JavaScript中由一个从底层源流出的ReadableStream对象表示。ReadableStream构造函数从给定的handlers中创建并返回一个可读的流对象。有两种类型的底层源:

推送(push)源当你访问它是,会不断的向你推送数据,你可以开始、暂停或取消对流的访问。示例包括实时视频流、server-sent events或WebSockets。
拉取(pull)源 要求你在连接到它们时显式地请求数据。例子包括通过fetch()或XMLHttpRequest调用的HTTP操作。

流数据以称为chunk的小块顺序读取。放置在流中的块称为进入队列。这意味着它们正在队列中等待被读取。内部队列会跟踪尚未读取的数据块。
队列策略是一个能流内部队列的状态,决定流应该如何发出Backpressure信号的对象。排队策略为每个chunk分配一个大小,并将队列中所有chunk的总大小与一个指定的数字(称为高水位标记high water mark)进行比较。
流中的块由reader读取。这个reader一次检索一个chunk,允许你对数据进行各种类型的操作。reader加上与之相伴的处理逻辑即被称为消费者(consumer)。
还有一个构件叫做控制器(controller)。每个可读流都有一个关联的控制器,顾名思义,它允许你控制流。
一次只能有一个reader读取流;当一个reader被创建并开始读取一个流(也就是说,成为一个活动的reader)时,它就被锁定在这个流上。如果你想让另一个reader接管你的流,你通常需要先释放第一个reader(尽管你可以tee流)。
创建一个可读流 #
你可以通过调用 ReadableStream()构造函数创建一个可读流。 这个构造函数有一个可选参数 underlyingSource, 它表示一个流实例将如何表现的方法和属性。
The underlyingSource #
可以使用以下的可选方法,由开发人员自定义:

start(controller): 在对象被构造的时立刻被调用。该方法可以访问流的源,并执行设置流功能所需的任何其他操作。如果这个过程是异步完成的,该方法可以返回一个promise来表示成功或失败. controller 参数是一个ReadableStreamDefaultController.
pull(controller): 可以用于在获取chunks时控制流。只要流的内部chunks队列没有满,它就会被反复调用,直到队列达到最高水位。如果调用pull()的结果是一个promise,那么pull()将不会被再次调用,直到该promise fulfills。如果promise被reject,流就会出错。
cancel(reason): 当流的消费者取消流时被调用.

posted @ 2024-08-14 07:41  巴伐利亚药水哥  阅读(39)  评论(0)    收藏  举报