stream 介绍
预计阅读时间: 6 分钟本篇来介绍一下 nodejs 当中的 stream 模块,我们也都知道流它其实并不是 nodejs 中所独创的一个概念,例如我们可以直接在类 unix 系统中去使用 ls | grep *.js 这样的命令,从而去过滤出以 js 结尾的文件,这个其实就是流操作的一种应用,它会将管道左侧命令执行之后得到的结果数据,然后再去交给右侧的命令来进行处理,这种通过流来操作数据的方式,无论在空间还是时间上的,都会具有明显的效率提升。
而 nodejs 诞生之初就是为了去解决 IO 密集型的 web 性能问题,其中最常用的两个模块文件系统和网络,他们就正是流操作的深度应用者,流其实就是一个处理流式数据的抽象接口,而 nodejs 里的 stream 模块则提供了用于实现流接口的对象,这个听起来可能会有一些绕,因为它本身就是在用流来解释流,因此对于流来说,我们需要多多使用才会更加的熟练。
为什么需要
那知道了流是什么之后,我们再来讨论一下,为什么程序开发中我们会采用流来去对数据进行处理,在这里我们就先去构建一个场景来进行说明,假设我们当前需要通过网络来观看一部高清的电影,它的大小是 1 个 g,那我们最终在客户端上看到它的大体流程就应该是这样的,首先应用程序会从服务器的磁盘中来读取 1 个 g 的内容,然后再去通过网络传输到客户端,最后客户端再去执行下载,由我们来去进行观看。
如果说应用程序在读取磁盘文件的时候采用的是 readFile 这样的方式,那么至少会存在两个常见的问题,第一个就是资源文件的读取是同步的,用户如果想要看到内容,则必须等待数据全部读取完成之后,才会去通过网络来进行传输,第二的话就是资源文件读取成功之后,需要一次性的全部去放到内存里,显然有一些时候内存空间是吃不消的,我们都知道在 nodejs 的底层采用的是 v8 引擎,而默认情况下,v8 所提供的内存大小也就是 1g 多一点,因此我们可以采用流来操作这个数据,我们可以先把资源文件像水一样一点一点的抽到一个池子里,然后再去选择需要的方式来抽干池子里的水,这样的话对于用户来说就可以分段的去看到资源里的内容,同时对内存的使用开销也会明显友好了很多。
当然除了数据的分段传输和内存减少使用之外,流操作还会有另外一个好处,就是可以配合着管道对分段的数据去进行需求的加工,例如说原始的数据是字符串,我们可以利用管道将它传给能够实现数据转换为 buffer 的单元,还可以再传给执行压缩操作的单元,只要类型支持语法正常,我们就可以一直往后去传递处理,直到最终来使用数据。
总结
简单的总结一下流处理数据的优势。
- 时间效率:流的分段处理可以同时操作多个数据 chunk
- 空间效率:同一时间流无须占据大内存空间
- 使用方便:流配合管理,扩展程序变得简单
nodejs 内置了 stream 模块,它实现了流操作。
stream 模块实现了四中流的分类的具体抽象,所有的流都继承自 EventEmitter。
- Readable: 可读流
- Writeable: 可写流
- Duplex: 双工流,即可读又可写
- Transform: 转换流,可读可写,还能实现数据转换