之前的内容都是在说 如何使用stream,比如说创建一个可读的stream,是通过fs模块创建的。创建一个可写的stream,那是http的response,是http模块提供的,所以目前为止,我们都在使用别人提供的stream。那么现在就是要 创建一个自己的流,给别人用
创建一个Writable Stream
const {Writable} = require("stream");
const outStream = new Writable({
write(chunk, encoding, callback){
console.log(chunk.toString())
callback()
}
})
process.stdin.pipe(outStream);
//保存文件为writable.js 然后用node运行
//不管你输入什么,都会得到相同的结果
process.stdin 是用户的输入stream ,通过管道流向我们自定义的outStream。数据传到了outStream,会把数据打印出来。一定要执行callback(),不然流不会停止。
运行该文件,并输入一些内容
我们输入什么,就打印什么
所以这个自定义的stream就是输入什么就打印什么,数据是从process.stdin这个进程的标准输入得到的。
创建一个Readable Stream
const { Readable } = require("stream");
const inStream = new Readable();
inStream.push("ABCDEFGHIJKLM");
inStream.push("NOPQRSTUVWXYZ");
inStream.push(null); // No more data
//inStream.pipe(process.stdout); 跟下面是一样的
inStream.on('data',(chunk)=>{
process.stdout.write(chunk)
console.log(`写数据了`)
})
// 保存文件为readable.js 然后 node 运行
当我们在push数据进inSteam的时候,它是处于静止态,因为可读的流默认是静止态,它是不会把数据发出去的。
只有当你监听了它的data事件的时候,就会变成流动态。
运行文件后效果:
push了两次有效数据,所有写了两次。
现在是把所有数据push进去了,然后监听data事件,这样不太好,要改进一下:
改进 readable.js
改进方案:默认不吐数据,等你问我要的时候,才吐出数据。
关键在于实现一个read方法
const { Readable } = require("stream");
const inStream = new Readable({
read(size) {
const char = String.fromCharCode(this.currentCharCode++)
this.push(char);
console.log(`推了 ${char}`)
if (this.currentCharCode > 90) { // 90 对应的是Z
this.push(null);
}
}
})
inStream.currentCharCode = 65 // 65对应的是A
inStream.pipe(process.stdout)
运行这个文件
所以,当你要写一个可读的流,最好等别人调用你的read再推,而不是先推好再等别人调。
当然两个方法都没有错,只是改完的这种更好。
因为这次的数据是按需供给的,对方调用read 我们才会给一次数据。
创建一个Duplex Stream
其实只要实现一个可读的流和一个可写的流就可以了
相当于把上面两个的代码复制一遍
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);
创建一个Transform Stream
这个既不用实现一个read方法,也不用实现一个write方法,只要实现一个transform方法就可以了。
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);
关键在于第5行代码: this.push(chunk.toString().toUpperCase());
调用chunk 就是读了,push 就是写了。就相当于 我读你的内容,再变化一下形式,再写给你,就跟babel一样。babel读你的es6,再变成es5,再写给你。
怎么使用:
第10行代码:process.stdin.pipe(upperCaseTr).pipe(process.stdout);
从用户的标准输入里面监听它的data事件,只要用户输入任何一个字,就会调用upperCaseTr这个transform流,这个transform流就会把用户输入的字变成大写的,然后把这些大写的字输出标准输出,用户就会看到自己输入的字变成大写的。
效果: