Skip to content
导航

stream 模块

流是用于处理 Node.js 中的流数据(例如流媒体)的抽象接口。

与其他数据处理方法相比,流基本上提供了两个主要优势:

  • 内存效率:在处理数据之前,无需在内存中加载大量数据
  • 时间效率:获得数据后立即开始处理数据,而不必等到整个有效载荷传输完毕后再进行处理

Node.js 中有 4 种类型的流:

  • Writable:可写流,可通过 fs.createWriteSteam() 创建
  • Readable:可读流,可通过 fs.createReadSteam() 创建
  • Duplex:双工流,即可读又可写,例如 net.Socket
  • Transform:转换流,也是一种双工流,可以对其他流进行数据转换

API

stream 模块提供用于实现流接口的 API。Node.js 提供了许多流对象,通常不需要使用 stream 模块来创建流。

可读流

  • 创建可读流 stream 模块有两种方法创建可读流

    • Readable
      js
      import { Readable } from 'stream'
      const readableStream = new Readable()
    • Readable.from( iterable, options )
      js
      Readable.from('Good morning!', {encoding: 'utf8'})
  • 向可读流发送数据

    js
    readableStream.push('ping!')
  • 从可读流读取数据 process.stdin 是一个可读流,参考命令行输入输出,有两种不同的读取方式:

    • 流动模式:当数据块可用时,可读流会发出数据事件,然后执行回调
      js
      let data = ''
      readableStream.on('data', chunk => data += chunk)
    • 暂停模式:调用 read() 从内部缓冲区读取数据并返回,没有数据时返回 null 用以终止循环
      js
      let data = ''
      readableStream.on('readable', , () => {
        let chunk
        while (null !== (chunk = readableStream.read())) {
          data += chunk
        }
      }

    可读流都以暂停模式开始,可以通过以下方法切换为流动模式:

    • readableStream.on('data', callback)
    • readableStream.resume()
    • readableStream.pipe()

    又可以通过以下方法切换回暂停模式:

    • readableStream.pause()
    • readableStream.unpipe() 删除管道以暂停因 pipe() 方法造成的流动。

可写流

  • 创建可写流 stream 模块只有一种方法创建可读流

    • Readable
      js
      import { Writable } from 'stream'
      const writableStream = new Writable()
  • 向可写流写入数据

    • write() + end()
      js
      writableStream.write('Hello ')
      writableStream.end('world!')
    • pipe() 将可读流的数据写入可写流
      js
      // 覆盖内置方法以观察写入数据
      writableStream._write = (chunk, encoding, next) => {
        console.log(chunk.toString())
        next()
      }
      readableStream.pipe( writableStream )

双工流

JavaScript 不支持多重继承,因此通过类 stream.Duplex 实现双工流。

stream.Duplex 原型继承自 stream.Readable,并寄生继承自 stream.Writable。因此具有可读流、可写流两者的API

转换流

转换流是双工流,但以一定方式将输入转换为输出。例如加密、解密、压缩、解压。

转换流原型继承自双工流,除了实现可读、可写外,还需实现 _transform() 方法,可选实现 _flush() 方法。

参考资料