Stream
案例一
Stream-流
释义:
stream是水流,但默认没有水
stream.write可以让水流中有水(数据)
每次写的小数据叫做chunk(块)
产生数据的一段叫做source(源头)
得到数据的一段叫做sink(水池)
案例二
案例三
Stream对象的原型链
s = fs.createReadStream(path)
-
那么它的对象层级为
-
自身属性(由
fs.ReadStream构造) -
原型:
stream.Readable.prototype -
二级原型:
stream.Stream.prototype -
三级原型:
events.EventEmitter.prototype -
四级原型:
Object.prototype
Stream对象都继承了EventEmitter
支持的事件和办法
drain
//stream1 一有数据就塞给 stream2
stream1.on('data', (chunk)=>{
const flag = stream2.write(chunk)
if(flag === false) {// dont write}
stream2.on('drain', ()=>{
go on write
})
})
// stream1停了,就停掉stream2
stream1.on('end', ()=>{
stream2.end()
})
注意:
事件里重点:data,end,drain,finish
方法内的重点:read,write
Stream分类
| 名称 | 特点 |
|---|---|
| Readable | 可读 |
| Writable | 可写 |
| Duplex | 可读可写(双向) |
| Transform | 可读可写(变化) |
Duplex相当于双向的马路,可以一边写一边读,但是,读和写没有交叉点,读和写的内容是不一样的内容,默认读和写的内容是分开的
Transform可以边写边读,可以自己写自己读,中间存在一个转换器(处理器)
Readable Stream
静止态paused和流动态flowing
-
默认处于paused态
-
添加data事件监听,它就变为flowing态
-
删掉data事件监听,它就变为paused态
-
pause()可以将它变为paused
-
resume()可以将它变为flowing
Writable Stream
drain流干了事件
-
表示可以加点水了
-
我们调用
stream.write(chunk)的时候,可能会得到false -
false的意思是你写太快了,数据积压了
-
这个时候我们就不能再write了,要监听
drain -
等
drain事件触发了,我们才能继续write
function writeOneMillionTimes(writer, data) {
let i = 1000000;
write();
function write() {
let ok = true;
do {
i--;
if (i === 0) {
// Last time!
writer.write(data);
} else {
// See if we should continue, or wait.
// Don't pass the callback, because we're not done yet.
ok = writer.write(data);
if (ok === false) {
console.log("不能再写了");
}
}
} while (i > 0 && ok);
if (i > 0) {
// Had to stop early!
// Write some more once it drains.
writer.once("drain", () => {
console.log("干涸了");
write();
});
}
}
}
const write = fs.createWriteStream("./big_file.txt");
writeOneMillionTimes(write, "hello world");
finish事件
- 调用
stream.end()之后,而且缓冲区数据都已经传给底层系统之后,触发finish事件。
创建流
创建一个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运行
不管输入什么,都会得到相同的结果
创建一个Readable Stream
const { Readable } = require("stream");
const inStream = new Readable();
inStream.push("ABCDEFGHIJKLM");
inStream.push("NOPQRSTUVWXYZ");
inStream.push(null);
inStream.pipe(process.stdout);
保存文件为readable.js 然后用node运行 我们先把所有数据都push进去了,然后pipe
const { Readable } = require("stream");
const inStream = new Readable({
read(size) {
this.push(String.fromCharCode(this.currentCharCode++));
if (this.currentCharCode > 90) {
this.push(null); //Z
}
},
});
inStream.currentCharCode = 65; //A
inStream.pipe(process.stdout);
保存文件为 readable2.js,然后用node运行 这次的数据是按需供给的,对方调用read我们才会给一次数据
Duplex Stream
Transform Stream
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);
内置的Transform Stream
Node.js中的Stream
| Readable Stream | Writable Stream |
|---|---|
| HTTP Response-客户端 | HTTP Request—客户端 |
| HTTP Request-服务端 | HTTP Response-服务端 |
| fs read stream | fs write stream |
| zlib stream | zlib stream |
| TCP sockets | TCP socks |
| child process stdout&stderr | child process stdin |
| process.stdin | process.srdin, process,stdin |
| 其他 | 其他 |