【Node.js】Stream(流)的学习笔记

  最近学习使用Node.js创建http proxy server,少不了要跟Stream打交道。昨天开始查阅一些资料,多少有了一些粗浅了解。整理在这里,供学习之用。

  从Node.js API文档中可知,

  "A stream is an abstract interface implemented by various objects in Node. For example a request to an HTTP server is a stream, as is stdout. Streams are readable, writable, or both. All streams are instances of EventEmitter。""流是很多I/0操作的抽象,被 Node 中的很多对象所实现。比如对一个 HTTP 服务器的请求是一个流(可读流)(服务器的响应是一个流(可写流)),stdout也是流。流是可读、可写或兼具两者的。所有流都是 EventEmitter 的实例。"

一.  为什么需要流(Stream)?

  举个例子,如果要读取一个文件,一次性读取需要占用大内存,是不可取的。因此就有了流,用流会很方便,可以帮我们避免这样的问题,调用其接口不用关心底层如何实现。

二. 什么是流(Stream)?

  流(Stream)是可读,可写或双工的。可以通过require('stream')加载流的基类,其中包括四类流, Readable 流、Writable 流、Duplex 流和Transform 流的基类。

  另外如果觉得上述四类基类流不能满足需求,可以编写自己的扩充类流。像我们Team现在正做的Node项目,就重写了Transform类以供使用。

  按照官方的API文档,步骤如下:

  1. 在您的子类中扩充适合的父类。(例如util.inherits(MyTransform, Transform); )
  2. 在您的构造函数中调用父类的构造函数,以确保内部的机制被正确初始化。
  3. 实现一个或多个特定的方法,参见下面的细节。

三. Readable流(可读流)介绍

   Readable(可读)流接口是对您正在读取的数据的来源的抽象。换言之,数据出自一个可读流。

   Readable 流有两种“模式”:流动模式暂停模式

   当处于流动模式时,数据由底层系统读出,并尽可能快地提供给您的程序;当处于暂停模式时,您必须明确地调用 stream.read() 来取出若干数据块。流默认处于暂停模式。

A. 通过以下三种方法,可读流会被切换到流动模式

     1. 添加一个'data'事件处理器来监听数据。

     2. 调用 resume()方法来明确开启数据流。

       3. 调用 pipe()方法将数据发送到一个可写流(Writable)。

     之前我一直对pipe()方法有疑问,不清楚其用法。现在了解,当我们用pipe()为可读流指定了一个接受者(可写流)的时候,数据才会真正的被从底层系统读出,传递给可写流。

B. 下面介绍Readable流有以下几种事件

     1. 'Readable'事件

     2. 'data'事件 - 数据正在传递时,触发该事件(以chunk数据块为对象)

     3. 'end'事件 - 数据传递完成后,会触发该事件。

     4. 'close'事件

     5. 'error'事件

所有这些事件都可以在官方API文档中找到例子。

C. 下面介绍Readable流很重要的一个方法,pipe()方法。

     该方法从可读流中拉取所有数据,并写入到所提供的目标(可写流)。该方法能自动控制流量以避免目标被快速读取的可读流所淹没。

     值得注意的是,默认情况下,当数据传送完毕,触发'end'事件时,会同时触发目标(可写流)的'end'事件,导致目标不再可写。

   举个简单的小例子,

 1 //http.js
 2 
 3 var http = require('http');
 4 var fs = require('fs');
 5 
 6 http.createServer(function(req, res){
 7     var stream = fs.createReadStream(__dirname + '/data.txt');
 8     stream.pipe(res);
 9 }).listen(3000);
10 
11 console.log('now we are listening 3000 port');

     data.txt文件内容如下:

     当执行此段代码后,用户访问http://127.0.0.1:3000/,会得到如下响应:

   此时,创建此Server后,用户访问请求过来,Server会创建一个可读流,当调用stream.pipe(res)为可读流指定目标后,可读流stream会开始从文件data.txt中读取数据,数据写入res(可写流)完毕后,自动调用res的end()方法,结束响应,可写流不再写入。

四. Writable流(可写流)介绍

Writable(可写)流接口是对写入数据的目标的抽象。

   可写流重要的两个方法,

   1. write()方法

     该方法向底层系统写入数据,并在数据被处理完毕后调用所给的回调。

   2. end()方法

   当不再写入数据时,调用该方法,停止写入。在调用end()后,再调用write()方法会产生错误。

五. 参考资料

   1. Node.js官方API文档

http://www.nodejs.org/api/stream.html

   2. 官方API文档中文版

http://nodeapi.ucdok.com/#/api/stream.html

   3. Node 中的流(Stream)

http://blog.segmentfault.com/xingrz/1190000000357044

   4. Node Streams: How do they work?

http://maxogden.com/node-streams.html

  抛砖引玉,继续加油。

  Best Regards

  Kevin Song 

                                                                                 - 2014/6/18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏pangguoming

Spring Boot集成JasperReports生成PDF文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲...

1.5K7
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

8918
来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

6088
来自专栏一个会写诗的程序员的博客

Spring Reactor 项目核心库Reactor Core

Non-Blocking Reactive Streams Foundation for the JVM both implementing a Reactiv...

2902
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

3017
来自专栏java 成神之路

使用 NIO 实现 echo 服务器

5737
来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

7436
来自专栏我和未来有约会

Silverlight第三方控件专题

这里我收集整理了目前网上silverlight第三方控件的专题,若果有所遗漏请告知我一下。 名称 简介 截图 telerik 商 RadC...

4435
来自专栏Golang语言社区

【Golang语言社区】GO1.9 map并发安全测试

var m sync.Map //全局 func maintest() { // 第一个 YongHuomap := make(map[st...

5548
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

5308

扫码关注云+社区