流 API - 可读流



在 Stream API 中,可读流是一个数据源,我们可以从中以顺序和异步的方式读取数据。它是一种标准化的从底层源获取数据的方式。底层源是网络上存在的资源。它们有以下两种类型:

推送源 - 当您访问数据时,数据会被推送给您。您可以控制流,例如何时启动、何时暂停甚至何时终止当前流。例如,视频游戏流。

拉取源 - 您需要显式地向它们请求数据。例如,使用 Fetch 或 XHR 调用访问文件。

在可读流中,数据以小块的形式存在,因此它被顺序读取,一次读取一块。一块可以是一个字节,也可以是更大的大小。因此,流中块的大小可能不同。现在让我们了解可读流是如何工作的。

可读流的工作原理

可读流的工作原理非常简单。在可读流中,数据块被放置在队列中。这意味着块正在队列中等待读取。这里我们还有一个内部队列,它跟踪未读取的块。块由读取器读取。它一次处理一个块的数据,并允许您对数据执行操作。一个读取器一次只能读取一个流。当读取器开始读取流时,该流对该读取器被锁定,这意味着不允许其他读取器读取该流。如果您想让另一个读取器读取该流,则必须终止第一个读取器或创建一个 tee 流。此外,每个读取器都有自己的控制器,允许您控制流,例如启动、关闭或暂停。

它还有一个使用者,负责处理从可读流接收到的数据并对其进行处理,并能够对其执行操作。

Readable Stream

可读流接口

Stream API 支持三种类型的可读流接口:

  • ReableStream 接口

  • ReableStreamDefaultReader 接口

  • ReadableStreamDefaultController 接口

ReadableStream 接口

ReadableStream 接口用于表示可读的数据流。它通常与 Fetch API 一起用于处理响应流。它还可以处理开发人员定义的流的响应流。

构造函数

为了为给定的处理程序创建一个可读流对象,ReadableStream 接口提供了一个 ReadableStream() 构造函数。

语法

const newRead = new ReadableStream()
Or
const newRead = new ReadableStream(UnderlyingSource)
Or
const newRead = new ReadableStream(UnderlyingSource, QueuingStrategy)

以下是 ReadableStream() 构造函数的可选参数:

UnderlyingSource - 此对象提供各种方法和属性,这些方法和属性定义了流实例的行为。方法包括:start()、pull() 和 cancel(),而属性包括:type 和 autoAllocateChunkSize。

QueuingStrategy - 此对象用于为给定的流定义排队策略。它采用两个参数:highWaterMark 和 size(chunk)。

实例属性

ReadableStream 接口提供的属性是只读属性。因此,ReadableStream 提供的属性是:

序号 属性和描述
1

ReadableStream.locked

此属性用于检查可读流是否被锁定到读取器。

方法

以下是 ReadableStream 接口常用的方法:

序号 方法和描述
1

ReadableStream.cancel()

此方法返回一个 promise,当流被取消时,该 promise 将被 resolve。

2

ReadableStream.getReader()

此方法用于创建读取器并将其锁定到流。在释放此读取器之前,不允许其他读取器使用。

3

ReadableStream.pipeThrough()

此方法用于创建一种可链接的方式,将当前流通过变换流进行管道传输。

4

ReadableStream.pipeTo()

此方法用于将当前 ReadableStream 管道传输到给定的 WriteableStream。当管道传输过程成功完成或由于某些错误而被拒绝时,它将返回一个 promise。

5

ReadableStream.tee()

此方法用于获取一个包含两个结果分支作为新的 ReadableStream 对象的二元素数组。

ReadableStreamDefaultReader 接口

ReadableStreamDefaultReader 接口用于表示默认读取器,该读取器将从网络读取流数据。它也可以从 ReadableStream 读取。

构造函数

要创建 readableStreamDefualtReader 对象,ReadableStreamDefaultReader 接口提供了一个 ReadableStreamDefaultReader() 构造函数。

语法

const newRead = new ReadableStreamDefaultReader(myStream)

此构造函数只包含一个参数 myStream。它将读取 ReadableStream。

实例属性

ReadableStreamDefaultReader 接口提供的属性是只读属性。因此,ReadableStreamDefaultReader 提供的属性是:

序号 属性和描述
1

ReadableStreamDefaultReader.closed

此属性返回一个 promise,当流关闭或由于某些错误而被拒绝时,该 promise 将被 resolve。它允许您编写一个程序,该程序将在流处理结束时做出响应。

方法

以下是 ReadableStream 接口常用的方法:

序号 方法和描述
1

ReadableStreamDefaultReader.cancel()

此方法返回一个 promise,当流被取消时,该 promise 将被 resolve。

2

ReadableStreamDefaultReader.read()

此方法返回一个 promise,该 promise 将访问流队列中的下一个块或片段。

3

ReadableStreamDefaultReader.releaseLock()

此方法用于移除读取器对流的锁定。

ReadableStreamDefaultController 接口

ReadableStreamDefaultController 接口表示一个控制器,它允许我们控制 ReadableStream 状态或内部队列。它不提供任何控制器,实例在构造 ReadableStream 时自动创建。

实例属性

序号 属性和描述
1

ReadableStreamDefaultController.desiredSize

此属性用于查找要填充流的内部队列的所需大小。

ReadableStreamDefaultController 接口提供的属性是只读属性。因此,ReadableStreamDefaultController 提供的属性是:

方法

以下是 ReadableStreamDefaultController 接口常用的方法:

序号 属性和描述
1

ReadableStreamDefaultController.close()

此方法用于关闭相关的流。

2

ReadableStreamDefaultController.enqueue()

此方法用于将指定的块或片段排入相关的流。

3

ReadableStreamDefaultController.error()

此方法将导致将来与相关流的任何交互都发生错误。

示例 - 创建 ReadableStream

在下面的程序中,我们将使用 ReadableStream 构造函数创建一个自定义可读流。首先,我们创建一个函数,该函数以块的形式生成数据。然后,我们使用包含 start() 函数的 ReadableStream() 构造函数创建一个可读流。此 start() 函数使用 pData() 递归函数,该函数在控制器的帮助下将数据从 myData() 函数推送到使用者,其中在每次推送操作之间设置 1 秒的超时。现在,我们创建一个读取器以使用 getReader() 函数从流中使用数据。然后,我们创建一个 readMyData() 函数,以读取器的帮助递归地从流中读取数据。当流结束时,done 标志被设置为 true,我们退出递归循环。

<!DOCTYPE html>
<html>
<body>
<script>
   // Function that produces data for the stream
   function* myData() {
      yield 'pink';
      yield 'blue';
      yield 'yellow';
      yield 'green';
   }
   // Create a readable stream using ReadableStream() function
   const readStream = new ReadableStream({
      start(controller) {
         const data = myData();

         // Adding data to the stream
         function pData() {
            const { done, value } = data.next();

            if (done) {
               // Close the stream if no more data is available
               controller.close();
               return;
            }
            // Pushing the data to the consumer
            controller.enqueue(value);

            // Continue pushing data after 1 sec
            setTimeout(pData, 1000);
         }
         // Calling the pData function to start pushing data
         pData();
      }
   });
   // Create a reader for the readable stream
   const myreader = readStream.getReader();
   function readMyData() {
      myreader.read().then(({ done, value }) => {
         if (done) {
            // Stream is closed
            console.log('Stream is closed');
            return;
         }
         // Processing the received data
         console.log('Received data:', value);

         // Continue reading the data 
         readMyData();
      });
   }
   // Calling readMyData() function to start 
   // reading data from the readable stream
   readMyData();
</script>
</body>
</html>

输出

Readable Stream

结论

这就是 Stream API 中的可读流。它们是 Stream API 中最重要和最常用的流。几乎所有 Web 浏览器(如 Chrome、Firefox、Opera、Edge、Safari 等)都支持它们。在下一篇文章中,我们将学习 Stream API 的可写流。

广告