目录
官网:Node.js Buffer(缓冲区) | 菜鸟教程
抽象的集合
- 使用流操作数据可以简化代码
- 使用流操作可以分段数据,配合管道设计的思想,可以自由加工和转换数据
- 在它的内部实现了一个 Stream 模块,这个模块就是使用流操作处理数据的抽象接口集合
- 在 node.js 中的流就像是一个工具包,它里面有很多小工具,不同的工具就对应着不同的数据操作
- 在 Node.js 中就实现了四种类型的流操作: 可读流,可写流,双工流,转换流
- 最开始的时候 ,js 操作字符串
- node平台下 js 操作二进制(buffer)
- 在使用 buffer 去执行数据 IO 的时候很不方便,因此就产生了流操作
- Node.js 里有一个模块叫 stream ,它里面实现了四个类( Readable Writable Duplex Transform )
- 我们在使用的时候分为二种情况:
- 一种就是 Node.js 内置的核心模块,它们本身就继承了流操作。(fs, net ,http, zlib)
- 另外一种就是在学习流操作时常做的行为,自定义流
- 我们在使用的时候分为二种情况:
// 模拟可读流的实现
let { Readable } = require('stream')
// 01.继承 Readable 类
// 02.重写它里面的 _read() 方法
class MyReadable extends Readable {
constructor(source) {
supper(source)
// 当前我们正在模拟的操作是可读流,它其实就是一个能够产生数据的 “黑盒”
// 因此这些一来我们就需要给它提供一些数据,用于模拟 底层数据 (磁盘上文件里的数据、程序中变量里的数据)
this.source = source
}
_read() {
// 将来我们从可读流里拿数据的时候,就按照要求调用 push 方法
// 当 push 被调用的时候,就会自动的往缓冲区里添加一个数据,供使用者将来去获取
// 而且 push 每执行一次,就意味着底层数据(source)中字节长度会少一些
// 所以终有一天,底层数据是会被消耗干的,这个时候我们需要告知缓存区,没数据了
// 此时只需要给 push 传入一个 null 值就可以了。
let data = this.source.shift() || null
this.push(data)
}
}
// 当前我利用一个数组存放数据来模拟底层数据
let source = ['zce', 'zcegg', 'syy']
// 01 可读流就是专门用于生产数据的流,我们也叫做数据源
// 02 在 pipe 管道设计中,可读流是处于 pipe 左侧的,也就是上游
let rs = new MyReadable (source)
// 03 请求,我闲着没事,造了一个可读流干吗?---》 如何来消费流当中的数据
// 数据的生产者,数据的消费者
// 04 对于 Readable 来说,它本身提供了二个事件用于我们消费数据。(data ,readable)
// 这里的 rs 居然能用 on 来订阅一个事件,就是因为 fs 模块不仅仅继承了 stream ,还继承了EventEmitter 类
rs.on('data', (chunk) => {
console.log(chunk.toString())
})
// 可读就是生产数据, 可写就是消费数据, 双工就是既可读又可写
let { Duplex } = require('stream')
class MyDuplex extends Duplex {
constructor(source) {
supper()
this.source = source
}
_read() {
let data = this.source.shift() || null
this.push(data)
}
_write(chunk, en, cb) {
// 可写流的操作就是在内部想办法把将来传进来数据 chunk 给消费掉
// 此时我选择的就是将传递进来的 chunk 写到标准输出当中
process.stdout.write(chunk.toString().toUpperCase())
// 当前的回调函数必须在 chunk 处理完成之后执行
// 这个执行一定要发生在chunk处理完之后
process.nextTick(cb)
}
}
let source = ['a', 'b', 'c']
let ds = new MyDuplex(source)
ds.on('data', (chunk) => {
console.log(chunk.toString())
})
// 只要是一个可写流,那就一定可以调用 write 方法
ds.write('aaa', 'utf-8', () => {
console.log('再坚持一会,zce来接我')
})
- 可读流就是生产数据
- 可写流就是消费数据
- 双工流可流可写
- 转换流本质上也是一个双工流,与 Duplex 不同的是它不仅仅可以实现读写操作,还可以在中间做自定义的数据转换,同时它的底层读写操作是打通的,这点 Duplex 是不具备的。
- src().pipe(rename()) .pipe(min-css())... .dest('dist)
- gulp 里的插件都是用 Node写的,核心就是导出一个具备一定功能的转换流