hello everybody
這篇文章我們來聊一下nodejs中的stream,也就是nodejs中的流。
什麼是流呢?從字面上來看我們應該可以想到水流,對吧。那我們不妨想一下水流有什麼特點呢?
比如我們日常生活中的水龍頭,流出來的水是有序且有方向的。
nodejs中的流也是一樣,是有序且有方向的。
nodejs中有許多的物件或者方法都用到了流。比如說HTTP 請求 和 process.stdout 就都是流的例項。
nodejs中的流可以是可讀的,可寫的或者是可讀寫的。而且另外一點,所有的流都是事件中EventEmitter的例項。
Node.js 中有四種基本的流型別:
Readable - 可讀的流 (例如 fs.createReadStream()).
Writable - 可寫的流 (例如 fs.createWriteStream()).
Duplex - 可讀寫的流 (例如 net.Socket).
Transform - 在讀寫過程中可以修改和變換資料的 Duplex 流 (例如 zlib.createDeflate()).
複製程式碼
我們先來看一下可讀流。
這樣我們就建立了一個可讀流,讀的是我們當前資料夾下的1.txt。我們來看一下官網對於可讀流的描述。
fs.createReadStream有以下監聽事件:
然後ReadStream類又繼承了Readble。
所以它又擁有下面這些事件:
所以就有了我們下面這些監聽的方法。我們來看一個完整的可讀流。
我們可以看到可讀流首先會開啟檔案->觸發檔案open事件,然後就開始瘋狂的觸發data事件讀取結束後會觸發end事件,然後將檔案關閉,並且觸發close事件。
我們注意這裡的data事件會不停的觸發,直到讀取完畢後結束。如果我們不想一次讀取完呢?這就要說到可讀流的兩種模式了。
我們先來看一下node文件中怎麼描述:
我們可以這樣理解:
flowing(流動模式)
paused(暫停模式)
複製程式碼
官方文件中介紹了,可讀流預設的模式是paused。切換的方法有三種,我們已經監聽data事件,這時可讀流的模式已經變成了flowing,如果我們想暫停需要怎麼做呢,我們看以下程式碼。
呼叫可讀流的pause方法就可以實現flowing->paused模式的切換。如果我們想再次讀取呢?
我們可以呼叫可讀流的resume方法來實現由paused->flowing模式的切換。
paused
在 paused 模式下,必須顯式呼叫 stream.read() 方法來從流中讀取資料片段。舉個例子:
我們根據上面的程式碼看一下執行的結果
可以看到我們消費了一個(rs.read(1))之後快取區的個數變成了2,由於低於了最低水位線,快取區又被加入了水位線的個數個。
可寫流
我們先來看下可寫流的簡單使用。
drain事件
drain事件的觸發條件是,當快取區有需要寫入的資料並且當快取區被清空時會觸發drain事件。
Pipe(管道)
我們在開發中可能會有入下場景,我們的可讀流讀出的資料需要放到可寫流中去寫入到檔案裡面,大約就有了如下程式碼。
可以看到資料是寫進來了,不過我們來想一想,我們一次讀5個但是一次寫入只寫入1個。還好我們的檔案夠小,快取區中放的東西也不多,但是如果我們的檔案很大呢?所以我們要改進一下我們的程式碼,基於可寫流返回的flag。
這樣基本上就實現了一個類似於管道的效果。不過官方提供了更便捷的方法。。
就是pipe。。我們來看下
pipe方法返回了一個可寫流物件。裡面有寫入內容等一些資訊,包括錯誤什麼的。其實思路跟我們之前的基本上是一樣的。
我們再來看一下pipe方法在node中的原始碼。
我們可以看到原始碼中同樣是通過drain方法來進行控制讀取檔案的頻率。
自定義流
自定義可讀流
自定義可寫流
與自定義可讀流基本類似,只不過繼承的方法不同。預設呼叫_write方法。
可讀寫流(雙工流)
也就是一個流中會同時有可讀流和可寫流存在並且互相不干擾;
轉換流(Transform)
我們可以看到我們使用了node的標準輸入和標準輸出。我們先把process.stdin(node中的標準輸入)雙工流的內容通過管道匯入到我們的可讀流transform1中,在把transform1中的內容匯入到transform2這個可寫流中,然後再寫入同樣是雙工流的process.stdout(node中的標準輸出)中。
我們在node環境中跑一下看看。
好了,說了這麼多差不多也該結束了。這一篇文章我們大致的瞭解了nodejs中的四種基本的流。還有一種物件流文章中沒有寫到,因為nodejs中用到物件流的地方很少。所以有興趣的同學可以去了解一下。
還是前面提到的,nodejs中用到流的地方有很多,類似於http和tcp中等等都有用到流。所以這個流還是很重要的。
我才疏學淺。也是懵懵懂懂的。有些地方也沒有講的很明白,大家多多包涵,如果有時間的話我們會在另一篇文章中來實現一下基於事件EventEmittenr的可讀流和可寫流。
好啦,不早了,就醬,Bye。
另外,祝好,謝謝大家看到這裡。