您好,登錄后才能下訂單哦!
這篇文章主要介紹了Nodejs中可寫流如何使用,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
可寫流是對數據流向設備的抽象,用來消費上游流過來的數據,通過可寫流程序可以把數據寫入設備,常見的是本地磁盤文件或者 TCP、HTTP 等網絡響應。
看一個之前用過的例子
process.stdin.pipe(process.stdout);
*process.stdout* 是一個可寫流,程序把可讀流 process.stdin 傳過來的數據寫入的標準輸出設備。在了解了可讀流的基礎上理解可寫流非常簡單,流就是有方向的數據,其中可讀流是數據源,可寫流是目的地,中間的管道環節是雙向流。
調用可寫流實例的 **write() **方法就可以把數據寫入可寫流
const fs = require('fs'); const rs = fs.createReadStream('./w.js'); const ws = fs.createWriteStream('./copy.js'); rs.setEncoding('utf-8'); rs.on('data', chunk => { ws.write(chunk); });
前面提到過監聽了可讀流的 data 事件就會使可讀流進入流動模式,我們在回調事件里調用了可寫流的 write() 方法,這樣數據就被寫入了可寫流抽象的設備中,也就是當前目錄下的 copy.js 文件。
write() 方法有三個參數
和自定義可讀流類似,簡單的自定義可寫流只需要兩步
我們來實現一個簡單的可寫流,把傳入可寫流的數據轉成大寫之后輸出到標準輸出設備(比較好的例子可能是寫入本地磁盤文件,但涉及過多的 fs 操作,比較麻煩,偷個懶。寫入標準輸出設備也是一種寫入行為)
const Writable = require('stream').Writable class OutputStream extends Writable { _write(chunk, enc, done) { // 轉大寫之后寫入標準輸出設備 process.stdout.write(chunk.toString().toUpperCase()); // 此處不嚴謹,應該是監聽寫完之后才調用 done process.nextTick(done); } } module.exports = OutputStream;
和最終可寫流暴露出來的 write() 方法一樣, _write() 方法有三個參數,作用類似
當然其實還有一個 _writev() 方法可以實現,這個方法僅被滯留的寫入隊列調用,可以不實現。
有了可寫流的類之后我們可以實例化使用了,實例化可寫流的時候有幾個 option 可選,了解一下可以幫助我們理解后面要用的知識
這樣我們就更清楚的知道 _write() 方法傳入的參數的含義了,而且對后面介紹 back pressure 機制的理解很有幫助。
和可讀流一樣,可寫流也有幾個常用的事件,有了可讀流的基礎,理解起來比較簡單
- pipe 當可讀流調用 pipe() 方法向可寫流傳輸數據的時候會觸發可寫流的 pipe 事件
- unpipe 當可讀流調用 unpipe() 方法移除數據傳遞的時候會觸發可寫流的 unpipe 事件
這兩個事件用于通知可寫流數據將要到來和將要被切斷,在通常情況下使用的很少。
writeable.write() 方法是有一個 bool 的返回值的,前面提到了 highWaterMark,當要求寫入的數據大于可寫流的 highWaterMark 的時候,數據不會被一次寫入,有一部分數據被滯留,這時候 writeable.write() 就會返回 false,如果可以處理完就會返回 true
drain 當之前存在滯留數據,也就是 writeable.write() 返回過 false,經過一段時間的消化,處理完了積壓數據,可以繼續寫入新數據的時候觸發(drain 的本意即為排水、枯竭,挺形象的)
除了 write() 方法可寫流還有一個常用的方法 end(),參數和 write() 方法相同,但也可以不傳入參數,表示沒有其它數據需要寫入,可寫流可以關閉了。
finish 當調用 writable.end() 方法,并且所有數據都被寫入底層后會觸發 finish 事件
同樣出現錯誤后會觸發 error 事件
了解了這些事件,結合上之前提到的可讀流的一些知識,我們就能探討一些有意思的話題了。在最開始我們提到過用流相對于直接操作文件的好處之一是不會把內存壓爆,那么流是怎么做到的呢?
最開始我們可能會想到因為流不是一次性把所有數據載入內存處理,而是一邊讀一邊寫。但我們知道一般讀取的速度會遠遠快于寫入的速度,那么 pipe() 方法是怎么做到供需平衡的呢?
回憶一些基礎知識,我們自己來實現一下 pipe() 方法的核心原理
我們可以利用這三點來做到數據讀取和寫入的同步,還是使用之前的例子,但為了使消費速度降下來,我們各一秒再通知完成
class OutputStream extends Writable { _write(chunk, enc, done) { // 轉大寫之后寫入標準輸出設備 process.stdout.write(chunk.toString().toUpperCase()); // 故意延緩通知繼續傳遞數據的時間,造成寫入速度慢的現象 setTimeout(done, 1000); } }
我們使用一下自定義的兩個類
const RandomNumberStream = require('./RandomNumberStream'); const OutputStream = require('./OutputStream'); const rns = new RandomNumberStream(100); const os = new OutputStream({ highWaterMark: 8 // 把水位降低,默認16k還是挺大的 }); rns.on('data', chunk => { // 當待處理隊列大于 highWaterMark 時返回 false if (os.write(chunk) === false) { console.log('pause'); rns.pause(); // 暫停數據讀取 } }); // 當待處理隊列小于 highWaterMark 時觸發 drain 事件 os.on('drain', () => { console.log('drain') rns.resume(); // 恢復數據讀取 });
結合前面的三點和注釋很容易看懂上面代碼,這就是 pipe() 方法起作用的核心原理。數據的來源的去向我們有了大概了解,后面可以開始介紹數據的加工
感謝你能夠認真閱讀完這篇文章,希望小編分享Nodejs中可寫流如何使用內容對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,遇到問題就找億速云,詳細的解決方法等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。