這篇文章主要介紹了Nodejs中可寫流如何使用,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:域名申請、虛擬空間、營銷軟件、網(wǎng)站建設(shè)、合作網(wǎng)站維護、網(wǎng)站推廣。可寫流是對數(shù)據(jù)流向設(shè)備的抽象,用來消費上游流過來的數(shù)據(jù),通過可寫流程序可以把數(shù)據(jù)寫入設(shè)備,常見的是本地磁盤文件或者 TCP、HTTP 等網(wǎng)絡(luò)響應(yīng)。
看一個之前用過的例子
process.stdin.pipe(process.stdout);
*process.stdout* 是一個可寫流,程序把可讀流 process.stdin 傳過來的數(shù)據(jù)寫入的標準輸出設(shè)備。在了解了可讀流的基礎(chǔ)上理解可寫流非常簡單,流就是有方向的數(shù)據(jù),其中可讀流是數(shù)據(jù)源,可寫流是目的地,中間的管道環(huán)節(jié)是雙向流。
調(diào)用可寫流實例的 **write() **方法就可以把數(shù)據(jù)寫入可寫流
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); });
前面提到過監(jiān)聽了可讀流的 data 事件就會使可讀流進入流動模式,我們在回調(diào)事件里調(diào)用了可寫流的 write() 方法,這樣數(shù)據(jù)就被寫入了可寫流抽象的設(shè)備中,也就是當前目錄下的 copy.js 文件。
write() 方法有三個參數(shù)
和自定義可讀流類似,簡單的自定義可寫流只需要兩步
我們來實現(xiàn)一個簡單的可寫流,把傳入可寫流的數(shù)據(jù)轉(zhuǎn)成大寫之后輸出到標準輸出設(shè)備(比較好的例子可能是寫入本地磁盤文件,但涉及過多的 fs 操作,比較麻煩,偷個懶。寫入標準輸出設(shè)備也是一種寫入行為)
const Writable = require('stream').Writable class OutputStream extends Writable { _write(chunk, enc, done) { // 轉(zhuǎn)大寫之后寫入標準輸出設(shè)備 process.stdout.write(chunk.toString().toUpperCase()); // 此處不嚴謹,應(yīng)該是監(jiān)聽寫完之后才調(diào)用 done process.nextTick(done); } } module.exports = OutputStream;
和最終可寫流暴露出來的 write() 方法一樣, _write() 方法有三個參數(shù),作用類似
當然其實還有一個 _writev() 方法可以實現(xiàn),這個方法僅被滯留的寫入隊列調(diào)用,可以不實現(xiàn)。
有了可寫流的類之后我們可以實例化使用了,實例化可寫流的時候有幾個 option 可選,了解一下可以幫助我們理解后面要用的知識
這樣我們就更清楚的知道 _write() 方法傳入的參數(shù)的含義了,而且對后面介紹 back pressure 機制的理解很有幫助。
和可讀流一樣,可寫流也有幾個常用的事件,有了可讀流的基礎(chǔ),理解起來比較簡單
- pipe 當可讀流調(diào)用 pipe() 方法向可寫流傳輸數(shù)據(jù)的時候會觸發(fā)可寫流的 pipe 事件
- unpipe 當可讀流調(diào)用 unpipe() 方法移除數(shù)據(jù)傳遞的時候會觸發(fā)可寫流的 unpipe 事件
這兩個事件用于通知可寫流數(shù)據(jù)將要到來和將要被切斷,在通常情況下使用的很少。
writeable.write() 方法是有一個 bool 的返回值的,前面提到了highWaterMark,當要求寫入的數(shù)據(jù)大于可寫流的 highWaterMark 的時候,數(shù)據(jù)不會被一次寫入,有一部分數(shù)據(jù)被滯留,這時候 writeable.write() 就會返回false,如果可以處理完就會返回 true
drain 當之前存在滯留數(shù)據(jù),也就是 writeable.write() 返回過 false,經(jīng)過一段時間的消化,處理完了積壓數(shù)據(jù),可以繼續(xù)寫入新數(shù)據(jù)的時候觸發(fā)(drain 的本意即為排水、枯竭,挺形象的)
除了 write() 方法可寫流還有一個常用的方法 end(),參數(shù)和 write() 方法相同,但也可以不傳入?yún)?shù),表示沒有其它數(shù)據(jù)需要寫入,可寫流可以關(guān)閉了。
finish 當調(diào)用 writable.end() 方法,并且所有數(shù)據(jù)都被寫入底層后會觸發(fā) finish 事件
同樣出現(xiàn)錯誤后會觸發(fā)error 事件
了解了這些事件,結(jié)合上之前提到的可讀流的一些知識,我們就能探討一些有意思的話題了。在最開始我們提到過用流相對于直接操作文件的好處之一是不會把內(nèi)存壓爆,那么流是怎么做到的呢?
最開始我們可能會想到因為流不是一次性把所有數(shù)據(jù)載入內(nèi)存處理,而是一邊讀一邊寫。但我們知道一般讀取的速度會遠遠快于寫入的速度,那么 pipe() 方法是怎么做到供需平衡的呢?
回憶一些基礎(chǔ)知識,我們自己來實現(xiàn)一下 pipe() 方法的核心原理
我們可以利用這三點來做到數(shù)據(jù)讀取和寫入的同步,還是使用之前的例子,但為了使消費速度降下來,我們各一秒再通知完成
class OutputStream extends Writable { _write(chunk, enc, done) { // 轉(zhuǎn)大寫之后寫入標準輸出設(shè)備 process.stdout.write(chunk.toString().toUpperCase()); // 故意延緩?fù)ㄖ^續(xù)傳遞數(shù)據(jù)的時間,造成寫入速度慢的現(xiàn)象 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(); // 暫停數(shù)據(jù)讀取 } }); // 當待處理隊列小于 highWaterMark 時觸發(fā) drain 事件 os.on('drain', () => { console.log('drain') rns.resume(); // 恢復(fù)數(shù)據(jù)讀取 });
結(jié)合前面的三點和注釋很容易看懂上面代碼,這就是 pipe() 方法起作用的核心原理。數(shù)據(jù)的來源的去向我們有了大概了解,后面可以開始介紹數(shù)據(jù)的加工
感謝你能夠認真閱讀完這篇文章,希望小編分享Nodejs中可寫流如何使用內(nèi)容對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,,關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,遇到問題就找創(chuàng)新互聯(lián)網(wǎng)站建設(shè)公司,,詳細的解決方法等著你來學(xué)習(xí)!