Node.js中的流(Stream)介绍


Posted in Javascript onMarch 30, 2015

什么是流?

说到流,就涉及到一个*nix的概念:管道——在*nix中,流在Shell中被实现为可以通过 |(管道符) 进行桥接的数据,一个进程的输出(stdout)可被直接作为下一个进程的输入(stdin)。

在Node中,流(Stream)的概念与之类似,代表一种数据流可供桥接的能力。

pipe

流化的精髓在于 .pipe()方法。可供桥接的能力,在于数据流的两端(上游/下游 或称为 读/写流)以一个 .pipe()方法进行桥接。

Node.js中的流(Stream)介绍

伪代码的表现形式为:

//上游.pipe(下游)

Readable.pipe(Writable);

流的分类

这里并不打算讨论所谓的Node  v0.4 之前的“经典”流。那么,流分为这么几类(皆为抽象接口:

1.stream.Readable    可读流(需要实现_read方法,关注点在于对数据流读取的细节
2.stream.Writable     可写流(需要实现_write方法,关注点在于对数据流写入的细节
3.stream.Duplex        可读/写流(需要实现以上两接口,关注点为以上两接口的细节
4.stream.Transform  继承自Duplex(需要实现_transform方法,关注点在于对数据块的处理

简单来说:

1).pipe() 的拥有者一定具备 Readable 流(并不局限于)能力,它拥有 'readable'/'data'/'end'/'close'/'error' 一系列事件可供订阅,也提供 .read()/.pause()/.resume()等一系列方法供调用;
2).pipe() 的参数一定具备Writable 流(并不局限于 )能力,它拥有 'drain'/'pipe'/'unpipe'/'error'/'finish' 事件可供访问,也提供 .write()/.end() 等一系列方法供调用

什么鬼

有没有一丝丝焦虑?别急,做为一个说人话的低级码工,我会把Stream掰开了和您扯一扯的。

Stream类,在 Node.js的源码 里,是这么定义的:

var EE = require('events').EventEmitter;

var util = require('util');

util.inherits(Stream, EE);

 

function Stream() {

  EE.call(this);

}

可以看出,本质上,Stream是一个EventEmitter,那意味着它具备事件驱动的功能(.emit/.on...)。众所周知,“Node.js 就是基于V8的事件驱动平台”,实现了事件驱动的流式编程,具备了和Node一样的异步回调的特征。

比如在 Readable 流中,有一个 readable 事件,在一个暂停的只读流中,只要有数据块准备好可读时,它就会被发送给订阅者(Readable 流有哪些呢?express中的 req,ftp或者mutli-form上传组件的req.part,系统中的标准输入 process.stdin等)。有了readable 事件,我们可以做个处理shell 命令输出的分析器之类的工具:

process.stdin.on('readable', function(){

   var buf = process.stdin.read();

   if(buf){

      var data = buf.toString();

      // parsing data ...                                                

   }

});

这样调用:

head -10 some.txt | node parser.js

对于 Readable 流,我们还可以订阅它的 data 和 end 事件,以获取数据块并在流枯竭时获得通知,如 经典socket示例 中那样:

req.on('connect', function(res, socket, head) {

    socket.on('data', function(chunk) {

      console.log(chunk.toString());

    });

    socket.on('end', function() {

      proxy.close();

    });

  });

Readable流状态的切换
需要注意的是,Readable 流有两种状态:flowing mode(激流) 和 pause  mode(暂停)。前者根本停不下来,谁被pipe上了就马上不停的给;后者会暂停,直到下游显式的调用 Stream.read() 请求才读取数据块。Readable 流初始化时是 pause mode的。

这两种状态可以互为切换的,其中,

有以下任一行为,pause 转 flowing:

1.对 Readable 流添加一个data事件订阅
2.对 Readable 调用 .resume() 显式开启flowing
3.调用 Readable 流的 .pipe(writable) ,桥接到一个 Writable 流上

有以下任一行为,flowing 转回 pause:

1.Readable 流还没有 pipe 到任何流上,可调 .pause() 暂停
2.Readable 流已经 pipe 到了流上,需 remove 掉所有 data 事件订阅,并且调用 .unpipe()方法逐一解除与下游流的关系

妙用

结合流的异步特性,我可以写出这样的应用:直接将 用户A 的输出桥接到 用户B 的页面上输出:

router.post('/post', function(req, res) {

    var destination = req.headers['destination']; //发给谁

    cache[destionation] = req;

    //是的,并不返回,所以最好是个ajax请求

});

用户B请求的时候:

router.get('/inbox', function(req, res){

    var user = req.headers['user'];

    cache.find(user, function(err, previousReq){ //找到之前存的req

       var form = new multiparty.Form();

       form.parse(previousReq);  // 有文件给我

       form.on('part', function (part) {

            part.pipe(res); //流式大法好:)

 

            part.on('error', function (err) {

                console.log(err);

                messaging.setRequestDone(uniqueID);

                return res.end(err);

            });

        });

    });

});

参考

how to write node programs with streams: stream-handbook

Javascript 相关文章推荐
一个简单的瀑布流效果(主体形式自写)
May 27 Javascript
Javascript:为input设置readOnly属性(示例讲解)
Dec 25 Javascript
ZeroClipboard插件实现多浏览器复制功能(支持firefox、chrome、ie6)
Aug 30 Javascript
node+express+jade制作简单网站指南
Nov 26 Javascript
jQuery插件pagination实现无刷新分页
May 21 Javascript
js从外部获取图片的实现方法
Aug 05 Javascript
JavaScript的new date等日期函数在safari中遇到的坑
Oct 24 Javascript
从零学习node.js之文件操作(三)
Feb 21 Javascript
微信小程序中的swiper组件详解
Apr 14 Javascript
JS运动特效之任意值添加运动的方法分析
Jan 24 Javascript
小程序扫描普通链接二维码跳转小程序指定界面方法
May 07 Javascript
原生JavaScript之es6中Class的用法分析
Feb 23 Javascript
Node.js 异步编程之 Callback介绍(一)
Mar 30 #Javascript
js动态修改表格行colspan列跨度的方法
Mar 30 #Javascript
jQuery使用hide方法隐藏页面上指定元素的方法
Mar 30 #Javascript
jquery使用hide方法隐藏指定id的元素
Mar 30 #Javascript
jQuery使用hide方法隐藏指定元素class样式用法实例
Mar 30 #Javascript
jQuery使用hide方法隐藏元素自身用法实例
Mar 30 #Javascript
javascript实现控制浏览器全屏
Mar 30 #Javascript
You might like
php格式化工具Beautify PHP小小BUG
2008/04/24 PHP
php导出excel格式数据问题
2014/03/11 PHP
php实现字符串翻转的方法
2015/03/27 PHP
PHP计算数组中值的和与乘积的方法(array_sum与array_product函数)
2016/04/01 PHP
php session的应用详细介绍
2017/03/22 PHP
js操作ajax返回的json的注意问题!
2010/02/23 Javascript
细说javascript函数从函数的构成开始
2013/08/29 Javascript
jquery实现图片左右切换的方法
2015/05/07 Javascript
举例简介AngularJS的内部语言环境
2015/06/17 Javascript
AngularJs页面筛选标签小功能
2016/08/01 Javascript
如何利用JQuery实现从底部回到顶部的功能
2016/12/27 Javascript
js常用的继承--组合式继承
2017/03/06 Javascript
在node中如何使用 ES6
2017/04/22 Javascript
浅谈JavaScript中的属性:如何遍历属性
2017/09/14 Javascript
vue.js-div滚动条隐藏但有滚动效果的实现方法
2018/03/03 Javascript
JavaScript设计模式--简单工厂模式定义与应用案例详解
2020/05/23 Javascript
基于python中pygame模块的Linux下安装过程(详解)
2017/11/09 Python
Python使用pyh生成HTML文档的方法示例
2018/03/10 Python
python如何实现视频转代码视频
2019/06/17 Python
对Pytorch中nn.ModuleList 和 nn.Sequential详解
2019/08/18 Python
win10环境下配置vscode python开发环境的教程详解
2019/10/16 Python
利用Python代码实现一键抠背景功能
2019/12/29 Python
Python常用模块sys,os,time,random功能与用法实例分析
2020/01/07 Python
在python中利用pycharm自定义代码块教程(三步搞定)
2020/04/15 Python
Python实现加密的RAR文件解压的方法(密码已知)
2020/09/11 Python
HTML5注册页面示例代码
2014/03/27 HTML / CSS
英国最大的汽车配件在线商店:Euro Car Parts
2019/09/30 全球购物
PHP两种查询函数array/row的区别
2013/06/03 面试题
htmlentities() 和 htmlspecialchars()有什么区别
2015/07/01 面试题
农民入党思想汇报
2014/01/03 职场文书
五年级语文教学反思
2014/01/30 职场文书
优秀共产党员演讲稿
2014/09/04 职场文书
优秀班主任推荐材料
2014/12/17 职场文书
导游词之云南丽江-泸沽湖
2019/09/26 职场文书
教你怎么用Python操作MySql数据库
2021/05/31 Python
jdbc中自带MySQL 连接池实践示例
2022/07/23 MySQL