NodeJS —— 自定义流的实现
概述
常见的自定义流有四种,Readable(可读流)、Writable(可写流)、Duplex(双工流)和 Transform(转换流),常见的自定义流应用有 HTTP 请求、响应,crypto 加密,进程 stdin 通信等等。
stream 模块介绍
在 NodeJS 中要想实现自定义流,需要依赖模块 stream,直接引入,不需下载,所有种类的流都是继承这个模块内部提供的对应不同种类的类来实现的。
实现一个自定义可读流 Readable
1、创建自定义可读流的类 MyRead
实现自定义可读流需创建一个类为 MyRead,并继承 stream 中的 Readable 类,重写 _read 方法,这是所有自定义流的固定套路。
let { Readable } = require("stream");
// 创建自定义可读流的类
class MyRead extends Readable {
constructor() {
super();
this.index = 0;
}
// 重写自定义的可读流的 _read 方法
_read() {
this.index++;
this.push(this.index + "");
if (this.index === 3) {
this.push(null);
}
}
}
复制代码
我们自己写的 _read 方法会先查找并执行,在读取时使用 push 方法将数据读取出来,直到 push 的值为 null 才会停止,否则会认为没有读取完成,会继续调用 _read。
2、验证自定义可读流
let myRead = new MyRead();
myRead.on("data", data => {
console.log(data);
});
myRead.on("end", function() {
console.log("读取完成");
});
// <Buffer 31>
// <Buffer 32>
// <Buffer 33>
// 读取完成
复制代码
实现一个自定义可写流 Writable
1、创建自定义可写流的类 MyWrite
创建一个类名为 MyWrite,并继承 stream 中的 Writable 类,重写 _write 方法。
let { Writable } = require("stream");
// 创建自定义可写流的类
class MyWrite extends Writable {
// 重写自定义的可写流的 _write 方法
_write(chunk, encoding, callback)) {
callback(); // 将缓存区写入文件
}
}
复制代码
写入内容时默认第一次写入直接写入文件,后面的写入都写入缓存区,如果不调用 callback 只能默认第一次写入文件,调用 callback 会将缓存区清空并写入文件。
2、验证自定义可写流
let myWrite = new MyWrite();
myWrite.write("hello", "utf8", () => {
console.log("hello ok");
});
myWrite.write("world", "utf8", () => {
console.log("world ok");
});
// hello ok
// world ok
复制代码
实现一个自定义双工流 Duplex
1、创建自定义可双工流的类 MyDuplex
双工流的可以理解为即可读又可写的流,创建一个类名为 MyDuplex,并继承 stream 中的 Duplex 类,由于双工流即可读又可写,需重写 _read 和 _write 方法。
let { Duplex } = require("stream");
// 创建自定义双工流的类
class MyDuplex extends Duplex {
// 重写自定义的双工流的 _read 方法
_read() {
this.push("123");
this.push(null);
}
// 重写自定义的双工流的 _write 方法
_write(chunk, encoding, callback)) {
callback();
}
}
复制代码
双工流分别具备 Readable 和 Writable 的功能,但是读和写互不影响,互不关联。
2、验证自定义双工流
let myDuplex = new MyDuplex();
myDuplex.on("readable", () => {
console.log(myDuplex.read(1), "----");
});
setTimeout(() => {
myDuplex.on("data", data => {
console.log(data, "xxxx");
});
}, 3000);
// <Buffer 31> ----
// <Buffer 32> xxxx
// <Buffer 32> ----
// <Buffer 33> xxxx
复制代码
如果 readable 和 data 两种读取方式都使用默认先通过 data 事件读取,所以一般只选择一个,不要同时使用,可读流的特点是读取数据被消耗掉后就丢失了(缓存区被清空),如果非要两个都用可以加一个定时器(绝对不要这样写)。
实现一个自定义转化流 Transform
1、创建自定义可转化流的类 MyTransform
转化流的意思是即可以当作可读流,又可以当作可写流,创建一个类名为 MyTransform,并继承 stream 中的 Transform 类,重写 _transform 方法,该方法的参数和 _write 相同。
let { Transform } = require('stream');
// 创建自定义转化流的类
class MyTransform extends Transform {
// 重写自定义的转化流的 _transform 方法
_transform(chunk, encoding, callback)) {
console.log(chunck.toString.toUpperCase());
callback();
this.push('123');
}
}
复制代码
在自定义转化流的 _transform 方法中,读取数据的 push 方法和 写入数据的 callback 都可以使用。
2、验证自定义转化流
// demo.js
let myTransForm = new MyTransform();
// 使用标准输入
process.stdin.pipe(myTransForm).pipe(process.stdin);
复制代码
打开命令行窗口执行 node demo.js,然后输入 abc,会在命令窗口输出 ABC 和 123,其实转换流先作为一个可写流被写入到标准输入中,而此时 stdin 的作用是读流,即读取用户的输入,读取后转换流作为一个可读流调用 pipe,将用户输入的信息通过标准输出写到命令行窗口,此时 stdout 的作用是写流。
总结
自定义流最常见的种类在上面都已经涵盖了,真正的在开发中用到的不多,如果需要写一个自定义流应该比上面的复杂很多,本文主要目的是认识什么是自定义流,并了解写一个自定义流的基本套路。
最后,顺便传播一个好消息:
想上线自己的后台系统或者做自己网站的,机会来了,腾讯云现做活动,新手福利1000减750,云服务器最低2折,云服务器1核2G内存50G硬盘3年最低只要600元!戳此了解详情!
作者:PandaShen
链接:https://juejin.im/post/5b5e2061e51d45339e7ed83c
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
NodeJS —— 自定义流的实现的更多相关文章
- activiti自定义流程之Spring整合activiti-modeler5.16实例(九):历史任务查询
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(八):完成个人任务
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(七):任务列表展示
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(六):启动流程
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(五):流程定义列表
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(四):部署流程定义
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(三):流程模型列表展示
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 (2)创建流程模型:activiti自定义流程之Spring ...
- activiti自定义流程之Spring整合activiti-modeler5.16实例(二):创建流程模型
注:(1)环境搭建:activiti自定义流程之Spring整合activiti-modeler5.16实例(一):环境搭建 1.maven导包,这里就没有什么多的好说了,直接代码: <depe ...
- NodeJS Stream流
NodeJS Stream流 流数据在网络通信中至关重要,nodeJS用Stream提供了一个抽象接口,node中有很多对象实现了这个接口,提供统一的操作体验 基本流类型 NodeJS中,Stream ...
随机推荐
- delphi的一些语法知识 以及参数传递问题,按引用方式传递参数,按值方式传递参数
//delphi中exit,abort,break,continue 的区别 exit: 退出函数体abort: 遇到异常,安静处理,就是不显示不提示break: 退出当前循环体,包括for ,whi ...
- 免费好用的Microsoft iSCSI Software Target 3.3
我们在搭建Windows群集的时候往往会使用到IP-SAN.但是面对昂贵的硬件IP-SAN,我们在学习和实验的环境中更加多的用到的往往是软件模拟的IP-SAN.今天就给大家介绍一个微软出品的免费iSC ...
- Jafka源码分析——LogManager
在Kafka中,LogManager负责管理broker上全部的Log(每个topic-partition为一个Log). 通过阅读源码可知其详细完毕的功能例如以下: 1. 依照预设规则对消息队列进行 ...
- QlikView格式化某一个单元格
QlikView中能够创建透视表和垂直表,或者一般的Table.假如有的时候须要某一个单元格的样式和其它单元格不一样.颜色或者边框宽度等.能够通过下面方式实现: 工具栏里面有个button叫:Desi ...
- WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化
WPF中的常用布局 一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...
- iOS xcode6最新提交app方法
依照之前方式打包.打包成功后.直接submit提交AppStore.然后再选择build,假设上传成功,但在build选择上未出现,你能够耐心等待.有可能要等上一天,然后选择相应的build,直接提交 ...
- Oracle新建数据库
确定楼主是以管理员身份登录的:1.首先,创建(新)用户: create user username identified by password; username:新用户名的用户名 password ...
- JSON入门指南
JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,很适合于server与 JavaScript 的交互.本文将高速解说 JSON 格式.并通过代码演示样 ...
- 2016/1/18 Java开发中的23种设计模式详解(转)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- Java编程中经常用到代码
http://www.toutiao.com/i6429293556086604289/