什么是 Stream?
定义:
流的英文 Stream,流(Stream)是一个抽象的数据接口,Node.js 中很多对象都实现了流,流是 EventEmitter 对象的一个实例,总之它是会冒数据(以 Buffer 为单位),或者能够吸收数据的东西,它的本质就是让数据流动起来。 可能看一张图会更直观:
注意:Stream 不是 Node.js 独有的概念,而是一个操作系统最基本的操作方式,只不过Node.js 有 API 支持这种操作方式。Linux 命令的 | 就是 Stream。
为什么要学习 Stream?
视频播放例子
小伙伴们肯定都在线看过电影,对比定义中的图-水桶管道流转图,Source 就是服务器端的视频,Dest 就是你自己的播放器(或者浏览器中的 Flash 和 H5 Video)。大家想一下,看电影的方式就如同上面的图管道换水一样,一点点从服务端将视频流动到本地播放器,一边流动一边播放,最后流动完了也就播放完了。
说明:视频播放的这个例子,如果我们不使用管道和流动的方式,直接先从服务端加载完视频文件,然后再播放。会造成很多问题
- 因内存占有太多而导致系统卡顿或者崩溃
- 因为我们的网速 内存 CPU 运算速度都是有限的,而且还要有多个程序共享使用,一个视频文件加载完可能有几个 G 那么大。
读取大文件 Data 的例子
有一个这样的需求,想要读取大文件 Data 的例子
使用文件读取
const http = require('http');const fs = require('fs');const path = require('path');const server = http.createServer(function (req, res) { const fileName = path.resolve(__dirname, 'data.txt'); fs.readFile(fileName, function (err, data) { res.end(data); });});server.listen(8000);
使用文件读取这段代码语法上并没有什么问题,但是如果 data.txt 文件非常大的话,到了几百M,在响应大量用户并发请求的时候,程序可能会消耗大量的内存,这样可能造成用户连接缓慢的问题。而且并发请求过大的话,服务器内存开销也会很大。这时候我们来看一下用Stream 实现。
const http = require('http');const fs = require('fs');const path = require('path');const server = http.createServer(function (req, res) { const fileName = path.resolve(__dirname, 'data.txt'); let stream = fs.createReadStream(fileName); // 这一行有改动 stream.pipe(res); // 这一行有改动});server.listen(8000);
使用 Stream 就可以不需要把文件全部读取了再返回,而是一边读取一边返回,数据通过管道流动给客户端,真的减轻了服务器的压力。
看了两个例子我想小伙伴们应该知道为什么要使用 Stream 了吧!因为一次性读取,操作大文件,内存和网络是吃不消的,因此要让数据流动起来,一点点的进行操作。
Stream 流转过程
再次看这张水桶管道流转图
图中可以看出,Stream 整个流转过程包括 Source,Dest,还有连接二者的管道 Pipe (Stream 的核心),分别介绍三者来带领大家搞懂 Stream 流转过程。
Stream 从哪里来-soucre
Stream 的常见 来源方式 有三种:
- 从控制台输入
- HTTP 请求中的 Request
- 读取文件
这里先说一下从控制台输入这种方式,2 和 3 两种方式 Stream 应用场景章节会有详细的讲解。
看一段 process.stdin 的代码
process.stdin.on('data', function (chunk) { console.log('stream by stdin', chunk) console.log('stream by stdin', chunk.toString())})//控制台输入koalakoala后输出结果stream by stdin stream by stdin koalakoala
运行上面代码:然后从控制台输入任何内容都会被 data 事件监听到,process.stdin 就是一个 Stream 对象,data 是 Stream 对象用来监听数据传入的一个自定义函数,通过输出结果可看出 process.stdin 是一个 Stream 对象。
说明: Stream 对象可以监听"data