nodejs stream基础知识
分类
nodejs 的 stream 有四种:
- Readable:可读流
- Writable: 可写流
- Duplex:双工流
- Transform:转换流
Readable
// _read方法是从底层系统读取具体数据的逻辑,即生产数据的逻辑。
// 在_read方法中,通过调用push(data)将数据放入可读流中供下游消耗。
// 在_read方法中,可以同步调用push(data),也可以异步调用。
// 当全部数据都生产出来后,必须调用push(null)来结束可读流。
// 流一旦结束,便不能再调用push(data)添加数据。
// 创建一个可以读的流,通过这个流对象监听数据
const stream = require('stream');
const Readable = stream.Readable;
class MyFileReader extends Readable {
constructor(options) {
super(options);
}
attachDataSource(dataSource) {
this.dataSource = dataSource;
}
// 实现 _read 方法
_read() {
// 通过 DataSource 传入数据
// 当 DataSource get 方法返回 null 会触发 Readable 的 end 事件,表示会结束
this.push(this.dataSource.get());
}
}
class DataSource {
constructor(size = 10) {
this.size = size;
this.data = [];
this.fill();
}
// 生产数据
fill() {
for (let index = 0; index < this.size; index++) {
this.data.push(index.toString());
}
}
// 获取数据
get() {
if (this.data.length === 0) {
return null;
}
return this.data.pop();
}
}
const dataSource = new DataSource();
const myFileReader = new MyFileReader();
myFileReader.attachDataSource(dataSource);
myFileReader.on('data', (data) => console.log('data: ' + data));
myFileReader.on('end', () => console.log('end'));
在 _read 方法里,可以调用 push 方法往缓冲池里放入数据,这里写的this.push(this.dataSource.get())方法是一个同步方法,获取完数据后立马再次执行 _read 方法获取下一条数据,如果你在_read 方法里写一个异步push 的数据
setTimeout(() => {
this.push(this.dataSource.get());
});
那么本次 _read 方法执行后,没有数据则不会执行下一次 _read 方法,直到 state 发生了变化,具体的细节可以参看:https://blog.csdn.net/shasharoman/article/details/80251512 这篇文章
Writable
// 上游通过调用writable.write(data)将数据写入可写流中。write()方法会调用_write()将data写入底层。
// 在_write中,当数据成功写入底层后,必须调用next(err)告诉流开始处理下一个数据。
// next的调用既可以是同步的,也可以是异步的。
// 上游必须调用writable.end(data)来结束可写流,data是可选的。此后,不能再调用write新增数据。
// 在end方法调用后,当所有底层的写操作均完成时,会触发finish事件。
const Writable = require('stream').Writable
class ToWritable extends Writable{
constructor(){
super();
}
_write(data, enc, next) {
// 将流中的数据写入底层
process.stdout.write(data.toString().toUpperCase());
// 写入完成时,调用`next()`方法通知流传入下一个数据
process.nextTick(next);
}
}
const writable = new ToWritable();
writable.on('finish', () => process.stdout.write('DONE'));
// 将一个数据写入流中
writable.write(`a\n`);
writable.write(`b\n`);
writable.write(`c\n`);
// 再无数据写入流时,需要调用`end`方法
writable.end();
Duplex
// 代码中实现了_read方法,所以可以监听data事件来消耗Duplex产生的数据。
// 同时,又实现了_write方法,可作为下游去消耗数据。
const Duplex = require('stream').Duplex
class ToDuplexable extends Duplex{
constructor(){
super();
this.limit = 0;
}
_write(buf, enc, next) {
this.limit ++ ;
next();
}
_read() {
if(this.limit--){
this.push('data');
}
// this.push(this.index++)
}
}
const toDuplexable = new ToDuplexable();
toDuplexable.on('data', data => process.stdout.write(data));
toDuplexable.on('end', () => process.stdout.write('DONE'));
toDuplexable.write('');
setTimeout(() => {
toDuplexable.write('');
toDuplexable.end();
}, 1000);
Transform
// Duplex 可读流中的数据(0, 1)与可写流中的数据('a', 'b')是隔离开的,但在Transform中可写端写入的数据经变换后会自动添加到可读端
//Tranform继承自Duplex,并已经实现了_read和_write方法,同时要求用户实现一个_transform方法。
const Transform = require('stream').Transform
class MyTransform extends Transform{
constructor() {
super()
}
_transform(buf, enc, next){
let res = buf.toString('utf8');
// 调用push方法将变换后的数据添加到可读端
this.push(`${res}_transform\n`);
// 调用next方法准备处理下一个
next();
}
}
var myTransform = new MyTransform();
myTransform.on('data', data => process.stdout.write(data));
myTransform.write('abc');
myTransform.write('def');
myTransform.end();
参考:
- 入门:https://tech.meituan.com/stream-basics.html
- 详解:https://github.com/zoubin/streamify-your-node-program
- Node.js Stream - 进阶篇:http://fe.meituan.com/stream-internals.html
nodejs stream基础知识的更多相关文章
- 【NodeJS】基础知识
nodejs基础 nodejs允许自己封装模块,使得编写程序可以模块化,便于维护整理.在一个js文件中写完封装的函数或对象后,可以使用exports或module.exports来将模块中的函数暴露给 ...
- Stream基础知识
Stream API Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,但是将执行操作的时间交给具体实现来决定.例如,如果你希望计算某个方法的平均值,你可以在每个元素 ...
- 前端知识体系-NodeJS相关】NodeJS基础知识全面总结
NodeJS基础知识 1. Node的全局对象和全局变量 1.1 全局对象:所有模块都可以调用的 global:表示Node所在的全局环境,类似于浏览器的window对象. process:该对象表示 ...
- 1.nodejs权威指南--基础知识
1. 基础知识 1.1 全局作用域及函数 1.1.1 全局作用域 在nodejs中,定义了一个global对象,代表nodejs中的全局命名空间,任何全局变量.函数或对象都是该对象的一个属性值 1.1 ...
- JAVA基础知识|lambda与stream
lambda与stream是java8中比较重要两个新特性,lambda表达式采用一种简洁的语法定义代码块,允许我们将行为传递到函数中.之前我们想将行为传递到函数中,仅有的选择是使用匿名内部类,现在我 ...
- nodejs+gulp+webpack基础知识
nodejs+gulp+webpack基础知识 2019年08月22日 11:49:40 天府云创 阅读数 22 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文 ...
- NodeJs>------->>第三章:Node.js基础知识
第三章:Node.js基础知识 一:Node.js中的控制台 1:console.log.console.info 方法 console.log(" node app1.js 1> ...
- C#网络编程基础知识
C#网络编程基础知识一 1.IPAddress类 用于表示一个IP地址.IPAddress默认构造函数 public IPAddress(long address);一般不用 其中Parse()方法最 ...
- JAVA基础知识之网络编程——-网络基础(Java的http get和post请求,多线程下载)
本文主要介绍java.net下为网络编程提供的一些基础包,InetAddress代表一个IP协议对象,可以用来获取IP地址,Host name之类的信息.URL和URLConnect可以用来访问web ...
随机推荐
- Smart pointer 智能指针小总结
Smart pointer line 58之后smart pointer里的计数已经是0,所以会真正释放它引用的对象,调用被引用对象的析构函数.如果继续用指针访问,会出现如下图的内存访问异常.所以说如 ...
- saltstack内置执行模块groupadd
groupadd模块用于命令行管理用户组 salt.modules.groupadd.add(name, gid=None, system=False) 添加一个用户到指定GID 例:salt '*' ...
- 装服务器,测试数据库,简单的maven命令
[说明]今天总体回顾一下:大概是早上装服务器,下午测试数据库,晚上了解简单的maven命令 一:今日完成 1)在远程服务器的tomcat 设置好管理员的登录账号 2)登录tomcat 的项目管理 查看 ...
- 第三课 nodejs读取文件
//引入文件操作模块var fs = require('fs'); //读取文件 使用 回调函数 utf-8编码读取 a.txt在当前文件目录fs.readFile('a.txt','UTF-8',f ...
- 九度OJ 1336:液晶屏裁剪 (GCD)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:983 解决:228 题目描述: 苏州某液晶厂一直生产a * b大小规格的液晶屏幕,由于该厂的加工工艺限制,液晶屏的边长都为整数.最近由于市场 ...
- [ArcGIS]Oracle RAC下创建地理数据库(Create Enterprise Geodatabase)失败的解决方法
转载请注明原文地址:http://www.cnblogs.com/litou/p/8028843.html 环境:Oracle 11g 11.2.0.1.0(双节点RAC群集),ArcGIS Desk ...
- Python中pymysql模块详解
安装 pip install pymysql 使用操作 执行SQL #!/usr/bin/env pytho # -*- coding:utf-8 -*- import pymysql # 创建连接 ...
- Java的接口和抽象类(转发:http://www.importnew.com/18780.html)
深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...
- C#调用大漠插件
大漠插件是一个很不错的东西,在按键精灵和易语言里面用得很多,可以后台找图找字,写游戏自动脚本用得特别多.前面写一个微信的自动脚本,查了一些资料,易语言不太熟悉,按键精灵功能上可能不好实现,就找了些资料 ...
- 图片加载Picasso
https://github.com/square/picasso 基本用法 // 基本用法 // 普通加载图片 Picasso.with(PicassoActivity.this) .load(&q ...