【Node.js】Stream(流)的學習筆記

  最近學習使用Node.js建立http proxy server,少不了要跟Stream打交道。昨天開始查閱一些資料,多少有了一些粗淺瞭解。整理在這裏,供學習之用。html

  從Node.js API文檔中可知,node

  "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 的實例。"segmentfault

 

一.  爲何須要流(Stream)?api

  舉個例子,若是要讀取一個文件,一次性讀取須要佔用大內存,是不可取的。所以就有了流,用流會很方便,能夠幫咱們避免這樣的問題,調用其接口不用關心底層如何實現。服務器

 

二. 什麼是流(Stream)?函數

  流(Stream)是可讀,可寫或雙工的。能夠經過require('stream')加載流的基類,其中包括四類流, Readable 流、Writable 流、Duplex 流和Transform 流的基類。學習

  

  另外若是以爲上述四類基類流不能知足需求,能夠編寫本身的擴充類流。像咱們Team如今正作的Node項目,就重寫了Transform類以供使用。ui

  按照官方的API文檔,步驟以下:spa

  1. 在您的子類中擴充適合的父類。(例如util.inherits(MyTransform, Transform); )
  2. 在您的構造函數中調用父類的構造函數,以確保內部的機制被正確初始化。
  3. 實現一個或多個特定的方法,參見下面的細節。 

     

 

 

三. Readable流(可讀流)介紹code

   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

相關文章
相關標籤/搜索