它是什么
通过继承eventEmitter,实现异步操作;使用buffer使用实现读一部分写一部分(缓存功能),并且操作的是binary。
为什么要
读写大数据时:异步读写,避免堵塞,避免卡顿。
如何使用
模块概览
nodejs的核心模块,基本上都是stream的的实例,比如process.stdout、http.clientRequest。
对于大部分的nodejs开发者来说,平常并不会直接用到stream模块,只需要了解stream的运行机制即可(非常重要)。
而对于想要实现自定义stream实例的开发者来说,就得好好研究stream的扩展API了,比如gulp的内部实现就大量用到了自定义的stream类型。
const fs = require('fs');
fs.createReadStream('./sample.txt').pipe(process.stdout);
流的分类
在nodejs中,有四种stream类型:
Readable:数据可读,比如 fs.createReadStream()。
Writable:数据可写,比如 fs.createWriteStream()。
Duplex:可读可写,比如 net.Socket()。
Transform:数据可改,比如 zlib.createDeflate()(数据压缩/解压)。
常见的流
#数据可读:
http.IncomingRequest
fs.createReadStream()
process.stdin
#数据可写:
var fs = require('fs');
var filepath = './sample.txt';
var writeStram = fs.createWriteStream(filepath);
#可读可写:
net.Socket
#数据可改:
var zlib = require('zlib');
zlib.createGzip()
基本架构
# 引入类库
const { Duplex,Transform } = require('stream');
# 流的创建
#2 建双共流
class YmcDuplex extends Duplex {
constructor(options) {
super(options);
// ...
}
_write(chunk, encoding, callback) {
console.log('we write: ', chunk);
callback();
}
_read(size) {
this.push('read method');
this.push(null);
}
}
#2 建可改流
class YmcTransform extends Transform {
constructor(options) {
super(options);
}
_transform(chunk, encoding, done) {
const upperChunk = chunk.toString().toUpperCase()
this.push(upperChunk)
done()
}
_flush(cb){
/* at the end, output the our additional info */
this.push('this is flush data\n')
cb(null, 'appending more data\n')
}
}
# 流的操作
#2 操双功流
#3 创建实例
const dp = new YmcDuplex({
readableObjectMode: true
})
#3 设置事件
#4 接收数据时执行
dp.on('data', (chunk) => {
console.log('we read: ', chunk)
})
#4 写入数据
dp.write('write method', 'utf-8')
#2 操可改流
#3 创建实例
const tss = new YmcTransform()
#3 接收数据
tss.pipe(process.stdout)
#3 写入数据
tss.write('hello transform stream\n')
tss.write('another line\n')
#3 写入结束
tss.end()
文件操作
# 引入类库
let fs = require("fs");
# 缓存数据
let data = '';
# 流的创建
#2 建可读流
let readerStream = fs.createReadStream('input.txt');
#流的操作
#2 操可读流
#3 设置编码
readerStream.setEncoding('UTF8');
#3 设置事件:data, end, and error
#4 收到数据时执行
readerStream.on('data', function(chunk) {
data += chunk;
});
#4 收完数据时执行
readerStream.on('end',function(){
console.log(data);
});
#4 出现错误时执行
readerStream.on('error', function(err){
console.log(err.stack);
});
某些语糖
#管道操作
readerStream.pipe(writerStream);
一些思考
01.如何避免回调地狱
既然基于事件模式,那么当代码越复杂时,越容易走进回调地狱(何时出现回调地狱
)。那么该如何避免呢?这是一种解决方案——将回调模式/事件模式转化为允诺模式(一点金光.它允诺化.jianshu)。
参考文献
chyingp.nodejs-learning-stream[P].cnblogs
runoob.nodejs-stream[P].runoob
斗米.Duplex-Stream-Transform-Stream[p].juejin
nodejs.offical-docs-srteam[p].
饥人谷.深入理解nodejs Stream模块[p].jianshu
wanghui-garcia."nodejs-stream部分".cnblogs