可读流 - nodejs stream总结
可读流
包含的事件:data,readable,end,close ,error,pause,resume
常用方法:resume,read,pipe,pause
客户端的 HTTP 响应
服务器的 HTTP 请求
fs 的读取流
zlib 流
crypto 流
TCP socket
子进程 stdout 与 stderr
process.stdin
实现可读流:
const {Readable} = require('stream');
let i = 0;
const rs = Readable({
encoding: 'utf8',
highWaterMark: 9,
// 这里传入的read方法,会被写入_read()
read: (size) => {
// size 为highWaterMark大小
// 在这个方法里面实现获取数据,读取到数据调用rs.push([data]),如果没有数据了,push(null)结束流
if (i < 10) {
// push其实是把数据放入缓存区
console.log(1);
rs.push(`当前读取数据: ${i++}`);
} else {
rs.push(null);
}
}
});
rs.on('readable', () => {
const data = rs.read(9)
console.log(data);
})
// 结果: 当前读取数据: 0 ..... 当前读取数据: 9
readable事件
触发时机 :当有数据可从流中读取时,就会触发readable 事件。如果流有新的动态,将会触发readable,比如push了新的内容;所以下面的代码将会触发两次readable;第二次之后缓冲区的内容多于highWaterMark,不再执行read方法,结果流没有变化,进而readable不再触发。
const {Readable} = require('stream');
let i = 0;
const rs = Readable({
encoding: 'utf8',
highWaterMark: 9,
read: (size) => {
if (i < 2) {
rs.push(`当前读取数据: ${i++}`);
} else {
rs.push(null);
}
}
});
// 在某些情况下,为 'readable' 事件附加监听器将会导致将一些数据读入内部缓冲区,也就是会调用read方法。
rs.on('readable', () => {
console.log(rs.readableFlowing); // false 进入暂停模式
const data = rs.read(1)
console.log(data);
})
// 结果 : 当 前
当到达流数据的尽头时, readable事件也会触发,但是在end事件之前触发,上面代码修改一下:
rs.on('readable', () => {
console.log('readable');
let data = ''
while (data=rs.read(1)){
console.log(rs.readableLength);
}
console.log(data);
})
// 在缓冲区内没有数据之后rs.readableLength为0,结尾有两个readable打印出来,最后一个代表流数据到达了尽头触发了readable
readable事件表明流有新的动态:要么有新的数据,要么到达流的尽头。 对于前者,stream.read() 会返回可用的数据。 对于后者,stream.read() 会返回 null。
添加 readable事件句柄会使流自动停止流动,并通过 readable.read() 消费数据(调用一次内部read方法)。 如果 readable事件句柄被移除,且存在 data 事件句柄,无需resume,流会再次开始流动。
data 事件
当流将数据块传送给消费者后触发。 当调用
readable.pipe(),readable.resume()或绑定监听器到data事件时,流会转换到流动模式。 当调用readable.read()且有数据块返回时,也会触发data事件。将
data事件监听器附加到尚未显式暂停的流将会使流切换为流动模式。 数据将会在可用时立即传递。如果使用
readable.setEncoding()为流指定了默认的字符编码,则监听器回调传入的数据为字符串,否则传入的数据为Buffer。
const {Readable} = require('stream');
let i = 0;
const rs = Readable({
encoding: 'utf8',
// 这里传入的read方法,会被写入_read()
read: (size) => {
// size 为highWaterMark大小
// 在这个方法里面实现获取数据,读取到数据调用rs.push([data]),如果没有数据了,push(null)结束流
if (i < 6) {
rs.push(`当前读取数据: ${i++}`);
} else {
rs.push(null);
}
},
destroy(err, cb) {
rs.push(null);
cb(err);
}
});
rs.on('data', (data) => {
console.log(data);
console.log(rs.readableFlowing); // true 进入流动模式
})
如果同时使用 readable事件和data事件,则 readable事件会优先控制流,readableFlowing为false;当调用 stream.read() 时才会触发 data事件
const {Readable} = require('stream');
let i = 0;
const rs = Readable({
encoding: 'utf8',
highWaterMark: 9,
read: (size) => {
if (i < 10) {
rs.push(`当前读取数据: ${i++}`);
} else {
rs.push(null);
}
}
});
rs.on('readable', () => {
const data = rs.read()
console.log(data);
console.log(rs.readableFlowing); // false
})
rs.on('data', (data) => {
console.log(rs.readableFlowing); // false
console.log(data);
})
// 即便用了data事件,因为由readable事件,可读流一直处于暂停模式
移除readable重新触发data事件
const {Duplex} = require('stream');
class Duplexer extends Duplex {
constructor(props) {
super(props);
this.data = [];
}
_read(size) {
const chunk = this.data.shift();
if (chunk == 'stop') {
this.push(null);
} else {
if (chunk) {
this.push(chunk);
}
}
}
_write(chunk, encoding, cb) {
this.data.push(chunk);
cb();
}
}
const d = new Duplexer({allowHalfOpen: true});
d.write('...大沙发撒地方是.');
d.write('阿斯顿发斯蒂芬');
d.write('阿斯顿发斯蒂芬11');
d.write('stop');
d.end()
var a = function (a) {}
d.on('readable', a);
d.on('data', function (data) {
console.log(data.toString());
});
d.removeListener('readable', a)
end 事件
只有在数据被完全消费掉后才会触发; 要想触发该事件,可以将流转换到流动模式,或反复调用 stream.read() 直到数据被消费完。
使用 readable.read() 处理数据时, while 循环是必需的。
const {Readable} = require('stream');
let i = 0;
const rs = Readable({
encoding: 'utf8',
highWaterMark: 9,
read: (size) => {
if (i < 2) {
rs.push(`当前读取数据: ${i++}`);
} else {
rs.push(null);
}
}
});
// 在某些情况下,为 'readable' 事件附加监听器将会导致将一些数据读入内部缓冲区,也就是会调用read方法。
rs.on('readable', () => {
while (data=rs.read(1)){
console.log(rs.readableLength);
}
})
rs.on('end', () => {
console.log('end');
})
highWaterMark
执行read方法的阈值;如果缓冲区内容长度大于highWaterMark,read方法将不会执行。
const {Readable} = require('stream');
let i = 0;
const rs = Readable({
encoding: 'utf8',
highWaterMark: 9,
read: (size) => {
if (i < 10) {
rs.push(`当前读取数据: ${i++}`);
} else {
rs.push(null);
}
}
});
rs.on('readable', () => {
console.log(rs.readableLength);
const data = rs.read(1)
console.log(data);
})
// 打印结果: 9 当 17 前
解析:第二次rs.read(1)时候,缓冲区的内容长度为16,大于highWaterMark,导致不能触发内部read方法。
resume pause close事件
这个例子使用了双工流
const {Duplex} = require('stream');
class Duplexer extends Duplex {
constructor(props) {
super(props);
this.data = [];
}
_read(size) {
const chunk = this.data.shift();
if (chunk == 'stop') {
this.push(null);
} else {
if (chunk) {
this.push(chunk);
}
}
}
_write(chunk, encoding, cb) {
this.data.push(chunk);
cb();
}
}
const d = new Duplexer({allowHalfOpen: true});
d.write('第一行');
d.write('第二行');
d.write('第三行');
d.write('stop');
d.end()
d.on('data', function (chunk) {
console.log('read: ', chunk.toString());
d.pause()
setTimeout(() => {
d.resume()
}, 2000)
});
d.on('pause',function () {
console.log('pause');
})
d.on('resume',function () {
console.log('resume');
})
d.on('close',function () {
console.log('close');
})
模式
可读流中分为2种模式流动模式和暂停模式。
1、流动模式:可读流自动读取数据,通过EventEmitter接口的事件尽快将数据提供给应用。
2、暂停模式:必须显式调用stream.read()方法来从流中读取数据片段。
暂停模式切换到流动模式i:
1、监听“data”事件
2、调用 stream.resume()方法
3、调用 stream.pipe()方法将数据发送到可写流
流动模式切换到暂停模式:
1、如果不存在管道目标,调用stream.pause()方法
2、如果存在管道目标,调用 stream.unpipe()并取消'data'事件监听
可读流 - nodejs stream总结的更多相关文章
- NodeJS Stream 五:双工流
双工流就是同时实现了 Readable 和 Writable 的流,即可以作为上游生产数据,又可以作为下游消费数据,这样可以处于数据流动管道的中间部分,即 rs.pipe(rws1).pipe(rws ...
- nodejs笔记之流(stream)
nodejs的stream有四种流类型: 可读:Readable可写:Writable可读可写:Duplex操作被写入数据,然后读出结果:Transform常用事件:data:有数据可读时触发end: ...
- NodeJS Stream流
NodeJS Stream流 流数据在网络通信中至关重要,nodeJS用Stream提供了一个抽象接口,node中有很多对象实现了这个接口,提供统一的操作体验 基本流类型 NodeJS中,Stream ...
- nodeJs文件系统(fs)与流(stream)
一.简介 本文将介绍node.js文件系统(fs)和流(stream)的一些API已经参数使用情况. 二.目录 文件系统将介绍以下方法: 1.fs.readFile 2.fs.writeFile 3. ...
- node.js中stream流中可读流和可写流的使用
node.js中的流 stream 是处理流式数据的抽象接口.node.js 提供了很多流对象,像http中的request和response,和 process.stdout 都是流的实例. 流可以 ...
- NodeJS Stream 三:readable
什么是可读流 可读流是生产数据用来供程序消费的流.我们常见的数据生产方式有读取磁盘文件.读取网络请求内容等,看一下前面介绍什么是流用的例子: const rs = fs.createReadStrea ...
- nodejs stream 手册学习
nodejs stream 手册 https://github.com/jabez128/stream-handbook 在node中,流可以帮助我们将事情的重点分为几份,因为使用流可以帮助我们将实现 ...
- Nodejs stream模块-翻译
花了两天时间尝试按照自己的话翻译了一下stream模块,以下内容皆翻译于:https://nodejs.org/api/stream.html. 目录 1 Stream(流) 1.1 ...
- nodejs stream基础知识
分类 nodejs 的 stream 有四种: Readable:可读流 Writable: 可写流 Duplex:双工流 Transform:转换流 Readable // _read方法是从底层系 ...
随机推荐
- Python并发编程03 /僵孤进程,孤儿进程、进程互斥锁,进程队列、进程之间的通信
Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 目录 Python并发编程03 /僵孤进程,孤儿进程.进程互斥锁,进程队列.进程之间的通信 1. 僵尸进程/孤儿进 ...
- 开源 5 款超好用的数据库 GUI 带你玩转 MongoDB、Redis、SQL 数据库
作者:HelloGitHub-*小鱼干 工欲善其事必先利其器,想要玩溜数据库,不妨去试试本文安利的 5 款开源的数据库管理工具.除了流行的 SQL 类数据库--MySQL.PostgreSQL 之外, ...
- OSCP Learning Notes - Enumeration(4)
DNS Enumeration 1. Host Tool host is a simple utility for performing DNS lookups. It is normally use ...
- Ethical Hacking - POST EXPLOITATION(3)
Spying - Capturing Key Strikes & Taking Screen Shots Log all mouse/keyboard events > keyscan- ...
- 记一次webpack打包的问题
记一次webpack打包的问题 在webpack打包中开启了webpack-bundle-analyzer,发现了一个chunk:tinymce  在整个项目中查找,只有一个未被使用的组件中有如下代 ...
- 深入浅出Semaphore源码解析
Semaphore通过permits的值来限制线程访问临界资源的总数,属于有限制次数的共享锁,不支持重入. 前提条件 在理解Semaphore时需要具备一些基本的知识: 理解AQS的实现原理 之前有写 ...
- node.js02 安装Node环境
安装Node环境 在node.js01中我大概了解了什么是node.js,这次进入起步阶段,首先要安装下Node环境. 开始安装 查看当前Node环境的版本号 win+r输入cmd进入命令行,输入no ...
- 一张PDF了解JDK11 GC调优秘籍-附PDF下载
目录 简介 废弃的VM选项 Source-File Mode Code Heap状态分析 AppCDS 总结 简介 JDK11相比JDK10,添加了一个新的Source-File Mode,可以直接通 ...
- WBF交易所如何使用二次验证码/谷歌身份验证器
一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接 WBF交易所如何使用二次验证码/谷歌身份验证器 二次验证码小程序于谷歌身份验证器APP的优势 1.无需下载app 2.验证码 ...
- Springboot(一)springboot简介与入门程序
一.springboot简介: 对spring框架盛行了多年的java方向开发人员来说,每个人java开发已经把spring框架当做开发中不可或缺的一部分. 之前传统的模式都是以application ...