理解Node.js中的stream

簡(jiǎn)介

主要對(duì)stream這個(gè)概念做一個(gè)形象的描述和理解翼闽,同時(shí)介紹一下比較常用的API株茶。主要參考了Node.js的官方文檔楣颠。

stream的種類(lèi)

stream解決的問(wèn)題

設(shè)計(jì) stream API 的一個(gè)關(guān)鍵目標(biāo)是將數(shù)據(jù)緩沖限制到可接受的級(jí)別拄衰,從而使得不同傳輸速率的源可以進(jìn)行數(shù)據(jù)的傳輸络拌,同時(shí)不會(huì)占用過(guò)量的內(nèi)存。比如擂送,文件的讀取悦荒。系統(tǒng)從硬盤(pán)中讀取文件的速度和我們程序處理文件內(nèi)容的速度是不相匹配的,而且讀取的文件可能是很大的嘹吨。如果不用流來(lái)讀取文件搬味,那么我們首先就需要把整個(gè)文件讀取到內(nèi)存中,然后程序從內(nèi)存中讀取文件內(nèi)容來(lái)進(jìn)行后續(xù)的業(yè)務(wù)處理蟀拷。這會(huì)極大的消耗系統(tǒng)的內(nèi)存碰纬,并且降低處理的效率(要先讀取整個(gè)文件,再處理數(shù)據(jù))问芬。

stream這個(gè)概念是很形象的悦析,就像是水流,可以通過(guò)管道此衅,從一處流向另一處强戴。比如從文件輸入,最終由程序接收挡鞍,進(jìn)行后續(xù)的處理骑歹。而 stream.pipe()就是流中最關(guān)鍵的一個(gè)管道方法。

// 此處代碼實(shí)現(xiàn)了從file.txt讀取數(shù)據(jù)墨微,然后壓縮數(shù)據(jù)道媚,然后寫(xiě)入file.txt.gz的過(guò)程
const r = fs.createReadStream('file.txt');
const z = zlib.createGzip();
const w = fs.createWriteStream('file.txt.gz');
r.pipe(z).pipe(w);

緩存機(jī)制

Writeable 和 Readable stream 都將數(shù)據(jù)存儲(chǔ)在一個(gè)自身內(nèi)部的buffer中。分別writable.writableBuffer or readable.readableBuffer 可以得到buffer的數(shù)據(jù)翘县。有一個(gè)參數(shù)highWaterMark 用來(lái)限制這個(gè)buffer的最大容量衰琐。從而使得流之間的數(shù)據(jù)傳輸可以被限制在一定的內(nèi)存占用下,并且擁有較高的效率炼蹦。

Writable Streams

幾個(gè)典型的可寫(xiě)流:
// 示例
const myStream = getWritableStreamSomehow();
myStream.write('some data');
myStream.write('some more data');
myStream.end('done writing data'); // 關(guān)閉流羡宙,不可再寫(xiě)入。
觸發(fā)的事件:
  • close
  • drain
    If a call to stream.write(chunk) returns false, the 'drain' event will be emitted when it is appropriate to resume writing data to the stream.
    不能無(wú)限制的寫(xiě)入掐隐,當(dāng)writeable stream的內(nèi)部緩存數(shù)據(jù)超過(guò)highWaterMark 的閾值狗热,stream.write會(huì)返回false,這是應(yīng)該停止寫(xiě)入虑省,等到觸發(fā)drain事件再繼續(xù)寫(xiě)入匿刮。
  • error
    注意,error事件觸發(fā)的時(shí)候探颈,stream不會(huì)自動(dòng)被關(guān)閉熟丸,需要手動(dòng)處理關(guān)閉。
  • finish
  • pipe
    對(duì)應(yīng)于readable.pipe(),有一個(gè)readable stream和該stream連通的時(shí)候觸發(fā)
  • unpipe
    對(duì)應(yīng)于readable.unpipe(),有一個(gè)readable stream和該stream管道斷開(kāi)的時(shí)候觸發(fā)

Readable Streams

幾個(gè)典型的可讀流:
兩種模式: flowing and paused

readable stream 創(chuàng)建時(shí)都為paused模式伪节,但是可以通過(guò)以下幾個(gè)方法變?yōu)閒lowing:

最常用的其實(shí)就是stream.pipe()了光羞。

觸發(fā)的事件:
  • close
  • data
  • end
  • readable
// 示例
const readable = getReadableStreamSomehow();
readable.on('data', (chunk) => {
  console.log(`Received ${chunk.length} bytes of data.`);
});
readable.on('end', () => {
  console.log('There will be no more data.');
});
readable.setEncoding(encoding)

調(diào)用readable.setEncoding('utf8')可以使得chunk的類(lèi)型由buffer變?yōu)閟tring绩鸣。

const readable = getReadableStreamSomehow();
readable.setEncoding('utf8');
readable.on('data', (chunk) => {
  assert.equal(typeof chunk, 'string');
  console.log('got %d characters of string data', chunk.length);
});

HTTP通信中的應(yīng)用

看代碼和注釋?xiě)?yīng)該就能懂了

const http = require('http');

const server = http.createServer((req, res) => {
  // req is an http.IncomingMessage, which is a Readable Stream
  // res is an http.ServerResponse, which is a Writable Stream

  let body = '';
  // Get the data as utf8 strings.
  // If an encoding is not set, Buffer objects will be received.
  req.setEncoding('utf8');

  // Readable streams emit 'data' events once a listener is added
  req.on('data', (chunk) => {
    body += chunk;
  });

  // the end event indicates that the entire body has been received
  req.on('end', () => {
    try {
      const data = JSON.parse(body);
      // write back something interesting to the user:
      res.write(typeof data);
      res.end();
    } catch (er) {
      // uh oh! bad json!
      res.statusCode = 400;
      return res.end(`error: ${er.message}`);
    }
  });
});

server.listen(1337);

// $ curl localhost:1337 -d "{}"
// object
// $ curl localhost:1337 -d "\"foo\""
// string
// $ curl localhost:1337 -d "not json"
// error: Unexpected token o in JSON at position 1
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纱兑,隨后出現(xiàn)的幾起案子呀闻,更是在濱河造成了極大的恐慌,老刑警劉巖潜慎,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捡多,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡铐炫,警方通過(guò)查閱死者的電腦和手機(jī)垒手,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)倒信,“玉大人科贬,你說(shuō)我怎么就攤上這事〉探幔” “怎么了唆迁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)竞穷。 經(jīng)常有香客問(wèn)我唐责,道長(zhǎng),這世上最難降的妖魔是什么瘾带? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任鼠哥,我火速辦了婚禮,結(jié)果婚禮上看政,老公的妹妹穿的比我還像新娘朴恳。我一直安慰自己,他們只是感情好允蚣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布于颖。 她就那樣靜靜地躺著,像睡著了一般嚷兔。 火紅的嫁衣襯著肌膚如雪森渐。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天冒晰,我揣著相機(jī)與錄音同衣,去河邊找鬼。 笑死壶运,一個(gè)胖子當(dāng)著我的面吹牛耐齐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼埠况,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼耸携!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起询枚,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤违帆,失蹤者是張志新(化名)和其女友劉穎浙巫,沒(méi)想到半個(gè)月后金蜀,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡的畴,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年渊抄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丧裁。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡护桦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出煎娇,到底是詐尸還是另有隱情二庵,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布缓呛,位于F島的核電站催享,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏哟绊。R本人自食惡果不足惜因妙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望票髓。 院中可真熱鬧哥蔚,春花似錦奥邮、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蹭劈,卻和暖如春减拭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背跷车。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工棘利, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人朽缴。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓善玫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茅郎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • stream 流是一個(gè)抽象接口蜗元,在 Node 里被不同的對(duì)象實(shí)現(xiàn)。例如 request to an HTTP se...
    明明三省閱讀 3,404評(píng)論 1 10
  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測(cè)試 ...
    KeKeMars閱讀 6,331評(píng)論 0 6
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理系冗,服務(wù)發(fā)現(xiàn)奕扣,斷路器,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 流是Node中最重要的組件和模式之一掌敬。在社區(qū)里有一句格言說(shuō):讓一切事務(wù)流動(dòng)起來(lái)惯豆。這已經(jīng)足夠來(lái)描述在Node中流...
    宮若石閱讀 552評(píng)論 0 0
  • Buffer Buffer的構(gòu)成 Buffer對(duì)象類(lèi)似數(shù)組,它的元素位16進(jìn)制的兩位數(shù)奔害,即0到255的數(shù)值楷兽。主要是...
    人失格閱讀 1,831評(píng)論 0 0