目录
一、流的原理
二、流的分类
1、可读流(ReadableStream)
3、转换流(TransformStream)
三、流中的Request和Response对象
四、综合应用
PS:涉及到一些基本的文件操作和格式内容知识,可以进入我的主页参考我之前的此系列文章。这个系列我还会继续更新下去的~
参考:
从 Fetch 到 Streams —— 以流的角度处理网络请求 - 掘金 (juejin.cn)
Stream API - Web API 接口参考 | MDN (mozilla.org)
在流之前,如果想要对文件资源进行操作,需要先下载完整的文件,等待它反序列化成合适的格式,在完整地对接收到的内容进行统一处理。流出现之后,网络发送文件可以将文件以一块块的数据形式传输,这使得——视频缓冲区 和 逐渐加载播放其他类型的资源成为可能。
*在阅读的时候,总会遇到一个词组叫做"Underlying Sink",我们翻译为"底层接收器"或者"底层汇聚器",指的是用于接收流写入数据的底层组件或实体,表达的是底层数据传输的目标或者终点。
流的优点:
- 在javascript中对流可以进行按块、按位处理,不再需要缓冲区、字符串或者blob;
- 你可以检测流何时开始或结束,将流链接在一起,根据需要处理错误和取消流,并对流的读取速度做出反应。
- 流的处理实现了异步,很多方法基于Promise,所以注意时序顺序
由于网络请求方法Fetch API,它区别于原始的XHR不仅仅在是基于Promise处理网络请求任务(XHR是基于事件驱动的callback),更是在于它是基于数据流来实现的。所以下文在描述流的操作时,不可避免要和fetch结合。另外,fetch API基于Request对象实现的,因此下文中提及的Request对象的基于流的使用和fetch API同理
1、可读流(ReadableStream)
表示数据的可读流。在使用Fetch进行网络请求处理时,请求对象中的body属性Request.body 和 响应对象Response.body 属性中可以获取到可读流的主体,这是将主体内容暴露作为一个可读流的 getter。
或者开发者可以自定义流(使用ReadableStream()进行构造,定义一些钩子比如start、cancel、pull等,参数的传入是controller控制器实例,同下文中提及的构造器参数)
举个应用栗子
ReadableStream中除了getReader()获取对可读流的读取器,还有一些常用方法:
- ReadableStream.tee():拷贝流,实现的是返回一个数组,包含对原始可读流的两个相同的副本可读流,然后可以独立的使用不同的 reader 读取
- 链式管道传输ReadableStream.pipeThrough()和ReadableStream.pipeTo():实现的是从一个流输出到另一个。前者pipeThrough是将可读流管道输出至拥有一对writer/reader 的流中比如下文介绍的TransformStream,并将一种数据转换成另一种类型的流(比如输入WritableStream->TransformStream->返回输出ReadableStream);后者pipeTo是可读流管道传输至作为链式管道传输终点的 writer(转换为readableStream->writableStream)
2、可写流(WritableStream)
为将流写入目的地(称为接收器)的过程,提供了一个标准抽象。内置了背压和队列机制。
*解释下背压和队列机制:
- 背压(Backpressure):
- 背压是指在数据写入速度大于消费者(读取端)的处理速度时,为了防止数据溢出,写入端必须采取一些措施以减缓写入速度的现象。
- 在可写流()中,当写入速度过快而消费者无法跟上时,可写流会发出背压信号,告诉写入端要减缓写入。这可以通过 返回的 Promise 来实现,当 Promise 处于挂起状态时,表示发生了背压。
- 队列机制:
- 队列机制是一种用于缓存待写入数据的机制,以确保写入端和消费者之间的速度匹配。
- 在 中,有一个内部的队列用于存储待写入的数据块。写入端通过 将数据块推送到队列中。如果队列已满或发生背压, 返回一个处于挂起状态的 Promise。
- 当队列中的数据被消费者处理时,队列中的下一个数据块会被写入。
定义构造WritableStream有两个对象参数:第一个必选,用于配置一些写入流时的钩子;第二个可选,用于配置一些chunk入队和队列控制的策略(利用ByteLengthQueuingStrategy【按字节计量】和CountQueuingStrategy【按元素数量计量】接口去定义策略)。
在必选中,所有的对象字段都是可选的,如下:
- start(controller):在WritableStream对象完成构造后立即调用controller method执行一次
- write(chunk,controller):每当一个新的chunk准备写入接收器的时候,将调用方法
- close(controller):当结束写入流时候调用该方法
- abort(reason):当写入流被中断或者写入流进入错误状态的时候,调用该方法
构造完的WritableStream可以用getWriter()方法获取其写入器
举个应用栗子
3、转换流(TransformStream)
代表一个即可写入又可读取的流,在读写之间起着中间流转换的作用。因此转换流比较简单,无实例方法,可自定义构造,只有两个只读的属性ReadableStream与 WritableStream,这两个都暴露的都是自身的可读流和可写流。通常,借助这两个属性来做中间转换!
举个应用栗子
实现输入的所有字符串都转为大写字母
这两个对象的很多属性依然和普通网络请求一样,可以直接通过对象获取,比如headers、request中的url和credentials等、response中的status等。
但是,在fetch和Request对象下,这两个对象的body属性返回的ReadableStream!
那么要如何转换成文件的其他资源格式和对象呢?request和response都有着相同的实例方法如下,只不过request是调用这些方法作为请求体body的内容格式,response是将响应体的body解析为对应格式:
直接单独说的是json()方法,request和response都有着相同的实例方法,可以将body内容兑现为json
但是response中还有一个静态方法json,可以在后端处理的时候,将输入的data直接以json格式塞入body而不是默认的readableStream;options配置status状态码、statusText状态信息、headers等,返回的是一个 以json内容为body 的response对象
举个应用栗子
fetch读取图像【涉及到如何从stream转为blob】
将彩色图片转成由灰度级别信息(grayscale)表示的黑白图,达成以下效果
github链接:dom-examples/streams/grayscale-png at main · mdn/dom-examples (github.com)
这里仅粘贴与流操作有关的核心代码,其中转换代码在png-lib.js里面,流读取在index.html中,有兴趣的去github看,里面还有不少其他例子~
transform:
流读取和转换:
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/5573.html