这里记录工作中遇到的技术点,以及自己对生活的一些思考,周三或周五发布。
封面图
Node中的streams流
streams流是Node中的最好的特性之一。它在我们的开发过程当中可以帮助我们做很多事情。比如通过流的方式梳理大量数据,或者帮我们分离应用程序。
和streams流相关的内容有哪些呢?大致有这么几点:
- 处理大量数据
- 使用管道方法
- 转换流
- 读写流
- 双工流
- 解耦I/O
双工流
双工流(duplex streams)既有可读接口又有可写接口。
我们可以使用duplexify模块将可读流和可写流作为双工流连接起来,当然这需要我们先install一下 duplexify 模块儿。
看个例子:
const from = require('from2')
const to = require('to2')
const duplexify = require('duplexify')
const rs = from(() => {
rs.push(Buffer.from('晚上好:terrence'))
rs.push(null)
})
const ws = to((data, enc, cb) => {
console.log('说的是:' + data.toString)
cb()
})
const stream = duplexify(ws, rs)
stream.pipe(stream)
执行上面的代码实际上打印出来的是toSting函数的函数体,因为我们的toString没加括号。
我们可以大致看一下这个过程,这也很正常,在学习一个问题的时候,顺带着可以理解另外一个问题。
我们给toString加上括号,可以看到,可以正常打印出我们push进去的数据。
代码中我们用到了之前提到过的from模块和to模块创建了可读流和可写流,但是和之前不同的是,我们声明了一个stream,并且用duplexify将rs和ws链接后的值赋给了stream。
这样,stream就可以用管道pipe到它自己。
这个场景非常有用,当我们想要返回或导出两个以某种方式相互关联的流时,这将会是一个非常有用的API。
I/O 解耦
stream流有两个主要的优势:一是通过增量处理可以对内存以及CPU进行比较精细的控制。二是这种简洁有力的API接口,可以在数据输入者,转换者,以及数据接收者,三者之间提供清晰的逻辑。
假设我们想要实现自定义的一个协议,最有可能的情况是它可能会需要或者跟TCP的服务一起使用。我们就可以从net模块儿的TCP服务中重新抽象出来新的内容,当然我们也可以提供一个和socket相关联的流。
看个例子:
这是tcp.js
const net = require('net')
const pump = require('pump')
const ping = require('../piping')
console.log('ping---', ping)
const server = net.createServer((socket) => {
const protocol = ping()
pump(socket, protocol, socket, closed)
})
function closed(err) {
if (err) {
console.log('链接出错----')
} else {
console.log('成功')
}
}
我们用net模块儿起了一个服务,然后接收到socket数据以后通过pump(泵)一层一层往下传递,给客户端返回数据,中间我们用protocol方法对数据做了处理。
然后我们看ping.js
const through = require('through2')
const split = require('split2')
const pumpify = require('pumpify')
function pingProtocal() {
const ping = /Ping:\s+(.*)/
const protocal = through(each)
function each(line, enc, cb) {
console.log('line--->', line.toString())
if (ping.test(line)) {
cb(null, `Pong:${line.toString().match(ping)[1]}\n`)
return
}
cb(null, '不符合规则')
}
return pumpify(split(), protocal)
}
module.exports = pingProtocal
ping.js中我们定义了pingProtocal方法,当我们检测到数据是以Ping:开头的时候,我们会将它转化成Pong。然后通过pumpify返回。
接下来我们在终端上输入:
node tcp.js
启动我们的服务。
然后开启另外一个终端,输入:
node -e "process.stdin.pipe(net.connect(4001)).pipe(process.stdout)"
和服务建立链接。
理论上当我们们在新的终端输入以Ping:开头的字符时,会收到服务端返回的以Pong开头的转化后的数据。
但是我这里失败了,报错如下:
起初我以为是我本地的端口被占用了,但是用
netstat -a | grep 3000
看了一下,好像也没问题,这就很奇怪。我们先不管这个问题,接着往下说。
这个例子的主要目的是作为一个演示解耦I/O的一个demo。
我们在处理输入数据的时候,往往在服务端会写一些接收到数据然后在进行处理的方法,这里主要是在TCP.js中,我们需要对接收到的socket进行处理,但是通过这种方式,我们可以将这个处理的过程单独拿出来进行处理,tcp.js中只要通过pump泵送数据即可。
同样的道理,假如我们需要对I/O进行压缩,或者加密,I/O我们可以理解为输入的数据或者输出的数据。我们就可以将它转换成流添加到管道中进行泵送。
道理都是相通的。
最后
- 公众号《JavaScript高级程序设计》
- 公众号内回复”vue-router“ 或 ”router“即可收到 VueRouter源码分析的文档。
- 回复”vuex“ 或 ”Vuex“即可收到 Vuex 源码分析的文档。
全文完,如果喜欢。
请点赞和"在看"吧,最好也加个"关注",或者分享到朋友圈。