说说node中的可读流和可写流的区别


Posted in Javascript onJune 01, 2018

前言

nodejs中大量的api与流有关,曾经看到公司的一些大神的node代码,实现一个接口只需要pipe一下另一个java接口就可以了。简单的一行代码实在让人困惑。作为小白的自己一脸懵逼却又不敢问,因为根本不知道从何问起。现在终于通过学习,也能对流说出个123,希望和大家共同交流。

流简介

流分为缓冲模式和对象模式,缓冲模式只能处理buffer或字符串,对象模式可以处理js对象。流又分为四种类型:可读流、可写流、双工流和转换流。后两种其实是对可读和可写流的应用。所以我想先聊聊可读流和可写流。

可读流

可读流有两种模式,并随时可以转换,我们可以通过监听可读流的事件来操作它。

两种模式(引用自node中文网的描述):

1、流动模式:可读流自动读取数据,通过EventEmitter接口的事件尽快将数据提供给应用。

2、暂停模式:必须显式调用stream.read()方法来从流中读取数据片段。

暂停模式切换到流动模式的api有:

1、监听“data”事件

2、调用 stream.resume()方法

3、调用 stream.pipe()方法将数据发送到可写流

流动模式切换到暂停模式的api有:

1、如果不存在管道目标,调用stream.pause()方法

2、如果存在管道目标,调用 stream.unpipe()并取消'data'事件监听

可读流事件:'data','readable','error','close','end'

可写流

可写流相对较为简单,我们也可以通过监听它的事件来操作它。

可写流事件: 'close','drain','error','finish','pipe','unpipe'

举个栗子

我以一个简单的例子描述一个流最常见的场景,谈谈对这个过程的理解。例子就是:我要读取一个文件,然后把它的内容写到另一个文件(当然是用“流”的api,而不是用‘fs'模块的api)。

说说node中的可读流和可写流的区别

接下来我解释一下这张图:

如上图,当我们创建了一个可读流的时候,readable._readableState.flowing属性默认为null,这时我们有两种选择:

1、监听‘readable'事件,这时可读流会读取64k(可以在创建可读流时,通过option参数中的highWaterMark更改)数据到流的缓存区中,等待你用read方法去读取并消费数据,当你用read方法读了64k数据之后,会再次触发readable事件,直到你读完了源文件的所有数据。记住,之所以叫暂停模式是因为如果你不调用read方法,代码永远会停在这里,什么事情也不会发生了。

2、如果你选择监听‘data'事件,可读流会直接读取64k数据并通过‘data'事件的回掉函数提供给你消费,并且这个过程不会停止,如果源文件中有很多数据,会不停的触发‘data'事件,直到全部读取完成。当然,在这个过程中你随时可以通过stream.pause()方法暂停它。

那么,这两种模式有什么区别呢?在我理解,如果你不需要对数据进行精确控制,首先选择流动模式,因为它的效率更高。如果需要对流的过程进行精确控制则可以选择暂停模式。也就是说暂停模式是流更高级一些的用法。其实官方建议我们尽量不要手动去操作流,如果可以,尽量使用pipe方法。

接下来,不论我们以哪种方式读到了文件中的数据,这时我们都可以创建一个可写流并调用可写流的write方法来消费读到的数据。调用write方法会向文件中写入数据,但是因为写入的速度较慢,如果当前写入还在进行,而你又调用了write方法,node会将你要写入的数据缓存在一个缓存区中,等到文件写入完毕会从缓存区中取出数据,继续写入。

write方法拥有一个布尔类型的返回值,用来表示目前是否还可以继续调用write方法写入内容。如果返回false,我们应当停止读取数据以避免消耗过多内存。那么什么时候会返false呢?就是当缓存区的大小大于16k(可以在创建可读流时,通过option参数中的highWaterMark更改)时。

缓存区满后,文件写入一直在进行,不一会儿会把缓存区的内容全部写入,缓存区处于清空状态,这时会触发可写流的‘drain'事件,这时我们可以继续向文件写入数据了。注意:如果缓存区从未满过,‘drain'事件永远也不会触发。

那么这张图对应到代码是什么样的呢:

let fs = require('fs');
//创建可读可写流
let rs = fs.createReadStream('./1.txt');
let ws = fs.createWriteStream('./2.txt');
//监听‘data'事件,开启流动模式
rs.on('data',function (data) {
  //对应图中的可写流true和false
  let flag = ws.write(data);
  if(!flag){
    //如果可写流返回false,我们应当停止读取,以避免消耗过多内存
    rs.pause();
  }
});

//对应图中的drain事件
ws.on('drain',function () {
  //重新开启流动模式
  rs.resume();
});

//使用可读流的暂停模式
function read() {
  let data = rs.read()
  let flag = ws.write(data);
  if(flag){
   read()
  }
}

rs.on('readable',function(){
  read()
})

ws.on('drain',function () {
  read()
});

结尾

可读和可写流的用法和api还有很多,这里只是简单的梳理了一下基本过程,如果有描述不准确的地方还请大家在评论区多指正。

参考资料

- https://nodejs.org/dist/latest-v8.x/docs/api/stream.html

- http://nodejs.cn/api/

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery Div中加载其他页面的实现代码
Feb 27 Javascript
jQuery 版本的文本输入框检查器Input Check
Jul 09 Javascript
JQuery防止退格键网页后退的实现代码
Mar 23 Javascript
一个CSS+jQuery实现的放大缩小动画效果
Feb 19 Javascript
jquery实现倒计时代码分享
Jun 13 Javascript
Struts2+jquery.form.js实现图片与文件上传的方法
May 05 Javascript
jQuery bt气泡实现悬停显示及移开隐藏功能的方法
Jul 12 Javascript
浅谈js数据类型判断与数组判断
Aug 29 Javascript
Node.js读取文件内容示例
Mar 07 Javascript
微信小程序开发的基本流程步骤
Jan 31 Javascript
js实现全选反选不选功能代码详解
Apr 24 Javascript
JS实现网页端猜数字小游戏
Mar 06 Javascript
Angularjs之如何在跨域请求中传输Cookie的方法
Jun 01 #Javascript
React 使用browserHistory项目访问404问题解决
Jun 01 #Javascript
详解vue-router 命名路由和命名视图
Jun 01 #Javascript
node.js利用socket.io实现多人在线匹配联机五子棋
May 31 #Javascript
JS与jQuery实现ListBox上移,下移,左移,右移操作功能示例
May 31 #jQuery
微信小程序登录换取token的教程
May 31 #Javascript
Rollup处理并打包JS文件项目实例代码
May 31 #Javascript
You might like
解密ThinkPHP3.1.2版本之模块和操作映射
2014/06/19 PHP
PHP基于数组实现的分页函数实例
2014/08/20 PHP
使用PHP和JavaScript判断请求是否来自微信内浏览器
2015/08/18 PHP
PHP通过反射动态加载第三方类和获得类源码的实例
2015/11/27 PHP
php图片合成方法(多张图片合成一张)
2017/11/25 PHP
使用PHP开发留言板功能
2019/11/19 PHP
Laravel中如何轻松容易的输出完整的SQL语句
2020/07/26 PHP
JavaScript 对象成员的可见性说明
2009/10/16 Javascript
使用JavaScript检测Firefox浏览器是否启用了Firebug的代码
2010/12/28 Javascript
有关JavaScript的10个怪癖和秘密分享
2011/08/28 Javascript
js中的内部属性与delete操作符介绍
2015/08/10 Javascript
JS实现超简单的仿QQ折叠菜单效果
2015/09/21 Javascript
详解js中常规日期格式处理、月历渲染和倒计时函数
2016/12/28 Javascript
微信小程序 video详解及简单实例
2017/01/16 Javascript
ajax实现加载页面、删除、查看详细信息 bootstrap美化页面!
2017/03/14 Javascript
layui 设置table 行的高度方法
2018/08/17 Javascript
JavaScript, select标签元素左右移动功能实现
2020/05/14 Javascript
vue.js实现双击放大预览功能
2020/06/23 Javascript
[01:31:02]TNC vs VG 2019国际邀请赛淘汰赛 胜者组赛BO3 第一场
2019/08/22 DOTA
[03:24][TI9纪实] Dota奶爸
2019/08/22 DOTA
Python基于最小二乘法实现曲线拟合示例
2018/06/14 Python
Python面向对象类编写细节分析【类,方法,继承,超类,接口等】
2019/01/05 Python
Python常见数字运算操作实例小结
2019/03/22 Python
django 基于中间件实现限制ip频繁访问过程详解
2019/07/30 Python
Python:合并两个numpy矩阵的实现
2019/12/02 Python
pytorch 实现张量tensor,图片,CPU,GPU,数组等的转换
2020/01/13 Python
python 写一个水果忍者游戏
2021/01/13 Python
应聘自荐书
2013/10/08 职场文书
应届生求职简历的自我评价怎么写
2013/10/23 职场文书
小学教师的个人自我鉴定
2013/10/24 职场文书
美工的岗位职责
2013/11/14 职场文书
淘宝客服工作职责
2014/07/11 职场文书
妇联领导班子剖析材料
2014/08/21 职场文书
2014乡镇干部纪律作风整顿思想汇报
2014/09/13 职场文书
教师党的群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
小学教师求职信范文
2015/03/20 职场文书