当前位置:网站首页>NodeJs原理 - Stream(二)
NodeJs原理 - Stream(二)
2022-08-10 12:12:00 【前端码农小王】
Duplex
创建可读可写流。
Duplex实际上就是继承了Readable和Writable的一类流。 所以,一个Duplex对象既可当成可读流来使用(需要实现_read方法),也可当成可写流来使用(需要实现_write方法)。
var Duplex = require('stream').Duplex
var duplex = Duplex()
// 可读端底层读取逻辑
duplex._read = function () {this._readNum = this._readNum || 0if (this._readNum > 1) {this.push(null)} else {this.push('' + (this._readNum++))}
}
// 可写端底层写逻辑
duplex._write = function (buf, enc, next) {// a, bprocess.stdout.write('_write ' + buf.toString() + '\n')next()
}
// 0, 1
duplex.on('data', data => console.log('ondata', data.toString()))
duplex.write('a')
duplex.write('b')
duplex.write('x')
duplex.end()
上面的代码中实现了_read方法,所以可以监听data事件来消耗Duplex产生的数据。 同时,又实现了_write方法,可作为下游去消耗数据。
因为它既可读又可写,所以称它有两端:可写端和可读端。 可写端的接口与Writable一致,作为下游来使用;可读端的接口与Readable一致,作为上游来使用。
Transform
在上面的例子中,可读流中的数据(0, 1)与可写流中的数据(’a’, ‘b’)是隔离开的,但在Transform中可写端写入的数据经变换后会自动添加到可读端。 Tranform继承自Duplex,并已经实现了_read和_write方法,同时要求用户实现一个_transform方法。
'use strict'
const Transform = require('stream').Transform
class Rotate extends Transform {constructor(n) {super()// 将字母移动`n`个位置this.offset = (n || 13) % 26}// 将可写端写入的数据变换后添加到可读端_transform(buf, enc, next) {var res = buf.toString().split('').map(c => {var code = c.charCodeAt(0)if (c >= 'a' && c <= 'z') {code += this.offsetif (code > 'z'.charCodeAt(0)) {code -= 26}} else if (c >= 'A' && c <= 'Z') {code += this.offsetif (code > 'Z'.charCodeAt(0)) {code -= 26}}return String.fromCharCode(code)}).join('')// 调用push方法将变换后的数据添加到可读端this.push(res)// 调用next方法准备处理下一个next()}
}
var transform = new Rotate(3)
transform.on('data', data => process.stdout.write(data))
transform.write('hello, ')
transform.write('world!')
transform.end()
数据类型
前面几节的例子中,经常看到调用data.toString()。这个toString()的调用是必需的吗?
在shell中,用管道(|)连接上下游。上游输出的是文本流(标准输出流),下游输入的也是文本流(标准输入流)
对于可读流来说,push(data)时,data只能是String或Buffer类型,而消耗时data事件输出的数据都是Buffer类型。对于可写流来说,write(data)时,data只能是String或Buffer类型,_write(data)调用时传进来的data都是Buffer类型。
也就是说,流中的数据默认情况下都是Buffer类型。产生的数据一放入流中,便转成Buffer被消耗;写入的数据在传给底层写逻辑时,也被转成Buffer类型。
但每个构造函数都接收一个配置对象,有一个objectMode的选项,一旦设置为true,就能出现“种瓜得瓜,种豆得豆”的效果。
1.Readable未设置objectMode时:
const Readable = require('stream').Readable
const readable = Readable()
readable.push('a')
readable.push('b')
readable.push(null)
readable.on('data', data => console.log(data))
2.Readable设置objectMode后:
const Readable = require('stream').Readable
const readable = Readable({ objectMode: true })
readable.push('a')
readable.push('b')
readable.push({})
readable.push(null)
readable.on('data', data => console.log(data))
可见,设置objectMode后,push(data)的数据被原样地输出了。此时,可以生产任意类型的数据。
边栏推荐
猜你喜欢

Solve the idea that unit tests cannot use Scanner

【论文+代码】PEBAL/Pixel-wise Energy-biased Abstention Learning for Anomaly Segmentation on Complex Urban Driving Scenes(复杂城市驾驶场景异常分割的像素级能量偏置弃权学习)

Guidelines for Sending Overseas Mail (2)

如何培养ui设计师的设计思维?

Comparison version number of middle questions in LeetCode

Does face attendance choose face comparison 1:1 or face search 1:N?

Crypto Gaming: The Future of Gaming
MySQL索引的B+树到底有多高?

IM即时通讯开发WebSocket从入门到精通

你是怎么知道数据库 Htap 能力强弱的?怎么能看出来
随机推荐
部署项目半途而废后续
娄底污水处理厂实验室建设管理
bat脚本——提取多个文件夹到指定路径
Loudi Sewage Treatment Plant Laboratory Construction Management
娄底干细胞制备实验室建设须知要求
Codeforces Round #276 (Div. 1) D. Kindergarten
娄底石油化工实验设计、建设规划概述
Dining (web stream)
【数字IC验证进阶】SoC系统验证和IP模块验证的区别及侧重点分析
47Haproxy Cluster
Chapter9 : De Novo Molecular Design with Chemical Language Models
MySQL相关问题整理
娄底植物细胞实验室建设基本组成要点
IM即时通讯开发WebSocket从入门到精通
【mysql索引实现原理】
Keithley DMM7510精准测量超低功耗设备各种运作模式功耗
娄底疾控中心实验室设计理念说明
How to do foreign media publicity to grasp the key points
A detailed explanation of implementation api embed
Mysql—— 内连接、左连接、右连接以及全连接查询