用简单的方法理解Node.js流
什么是蒸汽
流是Node.js中处理流数据的抽象接口
Streams不是Node.js的一个独特概念,它们是几十年前在Unix操作系统中引入的。
他们可以有效地处理文件读写、网络通信或任何类型的端到端信息交换。比如你写程序读文件,传统的方法是从头到尾把文件读入内存,然后处理。使用流,您可以逐块读取它并处理其内容,而无需将其全部保存在内存中。以下面的代码为例
const fs=require(' fs ');const RS=fs . CreateReadStream(' test . MD ');让数据=' ';rs.on('data ',function(chunk){ data=chunk;});rs.on('end ',function() {console.log(数据);});使用createReadStream创建一个数据读取流来读取test.md文件的内容,然后侦听数据事件,该事件在流将数据块传输给使用者后触发。在相应的事件处理程序中,拼接块。在结束事件中,打印到终端。在谈论流之前,您可以逐块读取文件内容,那么这是什么块,也就是区块?一般是Buffer,修改数据事件的eventHandler进行验证
rs.on('data ',function(chunk){ console . log(' chunk ',buffer . is buffer(chunk))//log true data=chunk;});流的工作模式可以具体表示为在内存中准备一个Buffer,然后在读取fs.read()时,将字节从磁盘逐步复制到Buffer。
为什么要使用Stream
使用Stream处理数据,主要是因为它有两个优点:
内存效率:不需要占用大量内存就可以处理数据;
时间效率:处理数据花费的时间更少,因为流逐块处理数据,而不是等待整个数据负载开始。
首先是内存效率,相比可以缓冲整个文件的fs.readFile,streaming充分利用了Buffer(大于8kb)不受V8内存控制的特点,利用堆外内存完成高效传输。请参考这篇博文,地址。与fs相比。FileSync,时间效率有一些优势,但与异步fs.readFile相比,优势不大。
流在节点中的使用
首先,用一张图片来了解Node.js中构建了哪些Stream接口
该图提供了一些Node.js本机流的例子,其中一些是可读和可写的。还有一些可读和可写的流,如TCP套接字、zlib和crypto。
特别注意:溪流的读写与环境息息相关。例如,HTTP响应在客户机上是可读的流,但在服务器上是可写的流。同时,需要注意的是,stdio流(stdin、stdout、stderr)在子进程上是相反的流。
用一个例子说明stream的用法
首先,使用以下脚本创建一个相对较大的文件(大约430 MB)
const fs=require(' fs ');const file=fs . createwritestream(' test . MD ');for(设I=0;i=1e6i ) {file.write('hello world。\ n ');} file . end();在当前目录下,启动http服务
const http=require(' http ')const fs=require(' fs ')const server=http . createserver(function(req,RES){ fs . readfile(_ dirname '/test . MD ',(err,Data)={res. end (data)})}) server。听(3000),如图所示
const http=require(' http ')const fs=require(' fs ')const server=http . createserver((req,RES)={ const stream=fs . createreadstream(_ _ dirname '/test . MD ')stream . pipe(RES)})server . listen(3000)
时间减少了2秒多。这可以解释为:在读取文件内容而不改变内容的场景下,流可以只读取缓冲区,然后直接传输,无需额外转换,避免了丢失,提高了性能。在上述代码中,stream.pipe(.)被应用。它主要是对对流进行链式管道操作,如
一种数据流,如src.pipe(dest1)。管道(dest2)是自动管理的。
如果可读流出现错误,目标可写流不会自动关闭,所有流都需要手动关闭,以避免内存泄漏。
通常在使用pipe方法时,不需要使用事件,但是如果场景需要以更加灵活和定制的方式使用流,则应该考虑事件。
流事件
在上面的例子中,我们使用可读流的数据和结束事件来控制文件的读取,例如,这本质上与管道方法相同
#可读. pipe(可写)可读. on('data ',(chunk)={可写. write(chunk);});可读. on('end ',()={可写. end();});但是,使用事件将更加灵活和可控。
图中简要列出了可读流和可写流的相关事件和方法,其中最重要的是
可读流:
数据事件:每当流经过大块数据时触发;End事件:当流中没有要发送的数据时触发。可写流:
排空事件:当数据可以继续写入流时,将触发该事件;完成事件:在处理完所有数据块后触发。不同类型的流
除了上面提到的读和写流,还有两种类型:双工和转换:
可读:您可以接收数据,但不能向其发送数据。当您将数据推入可读流时,它将被缓冲,直到消费者开始读取数据;可写:可以发送数据,但不能从中接收数据;双面:可读写;Tranform:和Duplex一样,它是可写可读的,但是它的输出和它的输入有关。如何创建可读的流
这里只简单介绍一下。详情见流模块。
常量流=需要('流')常量可读流=新流。可读()可读流。_ Read=(大小)={console。log ('read ',size)}使用流模块初始化一个可读的流,然后向它发送数据
readableStream.push('hi!')readableStream.push('ho!'如何创建可写流
为了创建可写流,有必要扩展基本的可写对象并实现其_write方法。
Const stream=require(' stream ')Const可写stream=newstream .可写()实现了_write方法:
可写流。_ write=(区块,编码,下一个)={console。日志(块。tostring ()) next ()}是用上面的例子实现的
使用readableStream读入数据并将其输出到writableStream
const Stream=require(' Stream ')const readableStream=new Stream。可读()readableStream。_read=(大小)={console.log('read ',size)} const writableStream=new Stream。可写()可写流。_write=(chunk,encoding,next)={console.log('write ',chunk . tostring())next()} readablestream . pipe(writableStream)readablestream . push(' hi!')readableStream.push('ho!')/* log:read 16384write hi!写嗬!*/以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。
版权声明:用简单的方法理解Node.js流是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。