最近學習使用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
三. 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