什么是Stream流?

stream是水流,但默认没有水(数据),如果要有水(数据),就使用stream.write有水(数据)。
每次写的一个小数据,就叫做chunk(块),产生数据的一段叫做source(源头),得到的数据的一段叫做sink(水池)。如图
Stream流 - 图1

例子代码:

  1. //引用node的fs模块
  2. const fs = require('fs');
  3. //对big_file.txt创建stream
  4. const stream = fs.createWriteStream('./big_file.txt');
  5. for(let i = 0; i < 10000; i++) {
  6. //对该文件进行10000次的写入
  7. stream.write(`第${i}行正在输入,输入了这些很多很多的内容`)
  8. }
  9. //写完后要关闭stream
  10. stream.end();

配合HTTP使用Stream

例子如下:

  1. const fs = require('fs');
  2. const http = require('http')
  3. const server = http.createServer();
  4. server.on('request', (request, response) => {
  5. fs.readFile('./big_file.txt', (error, data) => {
  6. if(err) throw err;
  7. response.end(data);
  8. })
  9. })
  10. server.listen(8888)

这样写的话,用户访问8888端口的时候,服务端就会很快的占用100多M的内存,一个用户还好,如果多个用户,就会撑爆服务器,所以需要进行优化。

stream.pipe的使用

上一个例子说明了占用内存过大的情况,可以使用pipe来解决:

  1. const fs = require('fs'); //引用node的fs模块
  2. const http = require('http')
  3. const server = http.createServer();
  4. server.on('request', (request, response) => {
  5. // fs.readFile('./big_file.txt', (error, data) => {
  6. // if(error) throw error;
  7. // response.end(data);
  8. // })
  9. const stream = fs.createReadStream('./big_file.txt');
  10. stream.pipe(response)
  11. })
  12. server.listen(8888)

该示例代码,相比上一个例子,占用内存最高不过30mb,会一点一点的传输到页面,而不是一股恼的全部传送。

pipe解释:
中文俗称“管道”,可以连接两个流,例如stream1流末尾连接到stream2流的开端,这样1号的数据就会流向2号的去。具体用法是这样的:
stream1.pipe(stream2)
当然,也可以一直连接下去:
stream1.pipe(stream2).pipe(stream3)
等价于:
stream1.pipe(stream2)
stream2.pipe(stream3)

可以不用pipe,用事件来实现管道:

  1. //stream1 一有数据的那一刻,就塞给stream2
  2. stream1.on('data', (chunk) => {
  3. stream2.write(chunk)
  4. })
  5. stream1.on('end', () => {
  6. stream2.end()
  7. })