博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
node的Stream解读
阅读量:5877 次
发布时间:2019-06-19

本文共 2518 字,大约阅读时间需要 8 分钟。

什么是stream

对数据输入输出的一个抽象

为什么要用 stream

在我们的需要是将一部电影返回给用户:

var fs = require('fs')var http = require('http')http.createServer((req,res)=>{    fs.readFile(moviePath, (err, data) => {        res.end(data);    });}).listen(8080)复制代码

这里就有几个问题:

  • 读取文件需要很长时间,导致用户会等待很久,
  • 读取的文件会很大,如果多个用户同时操作会占用极大的内存

stream改写

var fs = require('fs')var http = require('http')http.createServer((req,res)=>{    fs.createReadStream(moviePath).pipe(res)}).listen(8080)复制代码

这样每次都是只取一部分返回客户端,就不会有让客户端等待太久,内存占用也是有限的。

stream是如何解决问题

stream分类

  • 可读流:readable (例如:fs.createReadStream() )
  • 可写流:writable (例如:fs.createWriteStream() )
  • 可度可写流:duplex、transform

ps: node 中streamEventEmitter接口的实现类

readable

对于应用程序来说,可读取流可以看作:产生数据给程序使用的数据生产者。

在读取大数据的时候,并不是一次将数据读取出来,而是读取一部分,将这一部分放在内存中,并且当内存达到一定量(highWaterMark)的时候就会停止读取,直到数据被应用消费后清理出内存,才会再将读取数据放入内存。

可读流有两种模式:
  • 自动模式: 当数据内存没有达到 highWaterMark 自动生产数据
  • 手动模式: 每次生产数据需要用过手动产生

当我们在 data 下注册监听器的时候,就默认开启了自动模式。而在readable下注册监听器的时候,则默认开启的是手动模式。

在自动模式下,我们可以通过pause()方法来暂停自动模式,暂停后可以通过手动模式生产数据。通过resume()方法,可以恢复自动模式。

监听事件
  • error :当读取数据发生错误触发
  • end :数据读取完毕后触发

writable

对于应用来书,可写流可以看作:对产生的数据进行使用的消费者;

结合可读流,我们可以实现将读取的内容直接打印出来

var fs = require('fs')var http = require('http')var readStrem = fs.createReadStream(moviePath)http.createServer((req,res)=>{    readStrem.on("data",(trunk)=>{        res.write(trunk)    })}).listen(8080)复制代码

但时候这里存在一个问题,当我们写入速度小于读取数据时候就会产生问题。 所以我们需要某个时刻告诉生产者暂时生产,和恢复生产。可写流,则提供了一个待写入数据的列队池,生产数据过快时就会,将这一部分数据存入。当write()超过 列队池的highWaterMark就会返回false来告诉生产者停止生成,当列队池的数据被消费掉以后就会触发drain事件来告诉生产者继续生成。当我们写完后,就需要通过end()来结束写入,使用和write()相同

这个时候我们就需要改写成:

var fs = require('fs')var http = require('http')var readStrem = fs.createReadStream(moviePath)http.createServer((req,res)=>{    var writeStream = res    readStrem.on("data",(trunk)=>{        if(res.write(trunk) === false){            readStrem.pause()        }    })    writeStream.on("drain",()=>{         readStrem.resume()    })}).listen(8080)复制代码

这个也就是readable的pipe()实现过程

write(trunk[,encoding,callback])
  • trunk :写入数据(字符串或者buffer)
  • encoding:编码(如果数据是字符串,可以设置编码,buffer 或者 object 模式会忽略)
  • callback:数据写入后的回调函数,可以通知流传入下一个数据;当出现错误的时候也可以设置一个 error 参数
监听的事件
  • error 当写入出现错误的时候触发
  • finish 调用 end()事件后,且队列池内的数据被读取完毕的时候触发
  • pipe 当可读流通过pipe()方法将数据流入可写流的时候触发
var fs = require('fs')var readStrem = fs.createReadStream(moviePath)var writerStream = process.stdoutwriterStream.on('pipe',()=>{    console.log("有数据流入可写流")})readStrem.pipe(writerStream) //打印:有数据流入可写流复制代码
  • drain 当队列池中数据被读取完的时候触发

duplex、transform

duplex:可以看作继承了readablewritable 的实现类,重要的是输入和输出都是相互独立。 transform:时对输入和输出中间进行关联对数据进行加工。

参考:

转载地址:http://iiuix.baihongyu.com/

你可能感兴趣的文章
spring xml properties split with comma for list
查看>>
判断点是否在三角形内
查看>>
Android实战简易教程-第二十三枪(基于Baas的用户注冊验证username是否反复功能!)...
查看>>
在odl中怎样实现rpc
查看>>
leetcode 110 Balanced Binary Tree
查看>>
python活用isdigit方法显示系统进程
查看>>
项目开发总结
查看>>
知行合一
查看>>
jmeter插件之jsonpath提取响应结果和做断言
查看>>
发布支持多线程的PowerShell模块 —— MultiThreadTaskRunner
查看>>
Ubuntu ctrl+alt会导致窗口还原的问题
查看>>
第四十期百度技术沙龙笔记整理
查看>>
推荐系统那点事 —— 基于Spark MLlib的特征选择
查看>>
linux 下RTL8723/RTL8188调试记录(命令行)【转】
查看>>
開始新的征程
查看>>
SpringMVC案例1——对User表进行CRUD操作
查看>>
看雪CTF第十四题
查看>>
模拟生命_吸烟致癌?
查看>>
[Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统...
查看>>
Android 网络编程 记录
查看>>