【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

 

    

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM