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
相应的流(stdin
, stdout
, stderr
)在子进程中与主进程都是相反的流类型。这样一来主进程和子进程直接就可以方便地 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);