可读流

包含的事件: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总结的更多相关文章

  1. NodeJS Stream 五:双工流

    双工流就是同时实现了 Readable 和 Writable 的流,即可以作为上游生产数据,又可以作为下游消费数据,这样可以处于数据流动管道的中间部分,即 rs.pipe(rws1).pipe(rws ...

  2. nodejs笔记之流(stream)

    nodejs的stream有四种流类型: 可读:Readable可写:Writable可读可写:Duplex操作被写入数据,然后读出结果:Transform常用事件:data:有数据可读时触发end: ...

  3. NodeJS Stream流

    NodeJS Stream流 流数据在网络通信中至关重要,nodeJS用Stream提供了一个抽象接口,node中有很多对象实现了这个接口,提供统一的操作体验 基本流类型 NodeJS中,Stream ...

  4. nodeJs文件系统(fs)与流(stream)

    一.简介 本文将介绍node.js文件系统(fs)和流(stream)的一些API已经参数使用情况. 二.目录 文件系统将介绍以下方法: 1.fs.readFile 2.fs.writeFile 3. ...

  5. node.js中stream流中可读流和可写流的使用

    node.js中的流 stream 是处理流式数据的抽象接口.node.js 提供了很多流对象,像http中的request和response,和 process.stdout 都是流的实例. 流可以 ...

  6. NodeJS Stream 三:readable

    什么是可读流 可读流是生产数据用来供程序消费的流.我们常见的数据生产方式有读取磁盘文件.读取网络请求内容等,看一下前面介绍什么是流用的例子: const rs = fs.createReadStrea ...

  7. nodejs stream 手册学习

    nodejs stream 手册 https://github.com/jabez128/stream-handbook 在node中,流可以帮助我们将事情的重点分为几份,因为使用流可以帮助我们将实现 ...

  8. Nodejs stream模块-翻译

    花了两天时间尝试按照自己的话翻译了一下stream模块,以下内容皆翻译于:https://nodejs.org/api/stream.html. 目录 1  Stream(流)     1.1     ...

  9. nodejs stream基础知识

    分类 nodejs 的 stream 有四种: Readable:可读流 Writable: 可写流 Duplex:双工流 Transform:转换流 Readable // _read方法是从底层系 ...

随机推荐

  1. java 面向对象(四十二):反射(六)反射应用三:调用运行时类的指定结构

    调用指定的属性: @Test public void testField1() throws Exception { Class clazz = Person.class; //创建运行时类的对象 P ...

  2. 机器学习实战基础(十七):sklearn中的数据预处理和特征工程(十)特征选择 之 Embedded嵌入法

    Embedded嵌入法 嵌入法是一种让算法自己决定使用哪些特征的方法,即特征选择和算法训练同时进行.在使用嵌入法时,我们先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据权值系数从大 ...

  3. 数据可视化之DAX篇(三) 认识DAX中的表函数和值函数

    https://zhuanlan.zhihu.com/p/64421003 学习 DAX 的过程中,会遇到各种坑,刚开始甚至无法写出一个正确的度量值,总是提示错误.其实很多原因都是不理解 DAX 函数 ...

  4. linux专题(八):用户组管理

    http://dwz.date/UDf 每个用户都有一个用户组,系统可以对一个用户组中的所有用户进行集中管理.不同Linux 系统对用户组的规定有所不同,如Linux下的用户属于与它同名的用户组,这个 ...

  5. web自动化测试实战之批量执行测试用例

    01实战之分离测试固件 在UI 自动化测试中,不管编写哪个模块的测试用例,都需要首先在测试类中编写测试固件初始化WebDriver类及打开浏览器,执行登录,才能进行下一步业务逻辑的操作,测试用例执行完 ...

  6. Ethical Hacking - NETWORK PENETRATION TESTING(1)

    Pre--Connection-Attacks that can be done before connecting to the network. Gaining Access - How to b ...

  7. spring oauth2获取当前登录用户信息。

    使用spring oauth2框架做授权鉴定.想获取当前用户信息怎么办? 我们知道spring oauth2是基于spring security的实现的. spring security可以通过Sec ...

  8. swfupload控件文件上传大小限制设置

    swfupload控件,是我在开发过程中用到的上传文件的控件,非常实用和方便.但最近碰到一些问题,解决之后进行一下整理. 因为用户上传文件的大小限制增加,导致原本上传控件时,文件的大小需要进行调整和限 ...

  9. 亚马逊如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器?

    一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接  亚马逊如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器? 二次验证码小程序于谷歌身份验证器APP的优势 1.无需下载ap ...

  10. 关于简单的数据双向绑定原理,defineProperty 和Proxy演示

    双向绑定,也就是说js中的数据传到页面,页面中的内容到js,实现同步更新,简单的演示可以直接复制下放HTML代码运行. 在这个例子中,我们使用defineProperty ,Object.define ...