首页 > 技术文章 > 流的理解 1

honghong87 2018-09-19 11:14 原文

1:流(Stream)到底是什么?

流就是一系列的数据——就跟数组或者字符串一样。有一点不同,就是 stream 可能无法在一次性全部可用,且它们不需要与内存完全合槽。这么一来,stream 在处理大量数据,或者操作一个一次只给出一部分数据的数据源的时候显得格外有用。

其实,流不只是在操作大量数据的时候有用。它还为在代码中使用各种强大的组合类功能提供能力。例如,我们在 Linux 命令行中可以通过管道(pipe)来完成一些组合性的命令,在 Node.js 的流中也能实现。

2:掌握核心方法 readableStream.pipe(writableSrteam)

3:helloworld 

process.stdin.pipe(process.stdout);

4:很多 Node.js 的内置模块都是基于流接口的:

 

 

其中有一些对象甚至是既可读又可写的,例如 TCP socket、zlib 以及 crypto 等。

值得注意的是上面说的一些对象也是彼此紧密联系的。例如 HTTP 响应在客户端中是一个可读流,而在服务端则是一个可写流。毕竟在 HTTP 场景中,我们在客户端侧是从相应对象(http.IncommingMessage)读取数据,而在服务端则是写入数据(http.ServerResponse)。

还需要注意的是,stdio 相应的流(stdinstdoutstderr)在子进程中与主进程都是相反的流类型。这样一来主进程和子进程直接就可以方便地 pipe stdio 数据了。

Node.js 中的流有 4 种基本类型:Readable(可读流)、Writable(可写流)、Duplex(双工流)和 Transform(转换流)。

  • 可读流是对于可被消耗的数据源的抽象。例如 fs.createReadStream 方法;
  • 可写流是对于可被写入的数据目标的抽象。例如 fs.createWriteStream 方法;
  • 双工流是可读流与可写流的集合体。例如 TCP socket;
  • 转换流基本上就是一个双工流,只不过在读写的时候可以修改或者转化数据,例如 zlib.createGzip 就将数据使用 gzip 压缩了。你可以将变形金刚流看成是一个函数,其中输入是可写流,而输出是一个可读流。

所有的流都是继承自 EventEmitter。也就是说,它们触发的事件可以用于读写数据。不过,我们也可以简单粗暴地用 pipe 来消费流数据。

5:自己实现流

// 可读流
const inStream = new Readable({
  read(size) {
    this.push(String.fromCharCode(this.currentCharCode++));
    if (this.currentCharCode > 90) {
      this.push(null);
    }
  }
});
inStream.currentCharCode = 65;
inStream.pipe(process.stdout);
// 可写流
const { Writable } = require('stream');
const outStream = new Writable({
  write(chunk, encoding, callback) {
    console.log(chunk.toString());
    callback();
  }
});
process.stdin.pipe(outStream);
// 双工流
const { Duplex } = require('stream');
const inoutStream = new Duplex({
  write(chunk, encoding, callback) {
    console.log(chunk.toString());
    callback();
  },
  read(size) {
    this.push(String.fromCharCode(this.currentCharCode++));
    if (this.currentCharCode > 90) {
      this.push(null);
    }
  }
});
inoutStream.currentCharCode = 65;
process.stdin.pipe(inoutStream).pipe(process.stdout);
// 转换流
const { Transform } = require('stream');
const upperCaseTr = new Transform({
  transform(chunk, encoding, callback) {
    this.push(chunk.toString().toUpperCase());
    callback();
  }
});
process.stdin.pipe(upperCaseTr).pipe(process.stdout);

6:导图

 

推荐阅读