淺析Node.js的Stream模塊中的Readable對(duì)象
我一直都很不愿意扯 nodejs 的流,因?yàn)閺牡谝淮慰吹剿揖陀X(jué)得它的設(shè)計(jì)實(shí)在是太惡心了。但是沒(méi)辦法,Stream 規(guī)范尚未普及,而且確實(shí)有很多東西都依賴了 nodejs 的流來(lái)實(shí)現(xiàn)的,所以我也只能捏著鼻子硬著頭皮來(lái)扯一扯這又臭又硬的 nodejs 流對(duì)象了。
nodejs 自帶了一個(gè)叫 stream 的模塊,引入它便可以得到一組流對(duì)象構(gòu)造器。現(xiàn)在我只說(shuō)最簡(jiǎn)單的 stream.Readable。
其實(shí)用過(guò) nodejs 的幾乎都接觸過(guò) Readable 的實(shí)例,只是平時(shí)沒(méi)太在意而已。一個(gè)非常典型的例子,http 模塊中我們處理每個(gè)請(qǐng)求時(shí)都會(huì)有 req 和 res 對(duì)象,req 其實(shí)就是一個(gè) Readable 對(duì)象。我們可以在這個(gè) req 上以流的形式讀到 HTTP 請(qǐng)求的實(shí)體部分。
那么問(wèn)題來(lái)了,為什么 http 模塊要在此處以流的方式設(shè)計(jì)呢?或者從另一個(gè)維度來(lái)問(wèn)這個(gè)問(wèn)題就是「nodejs 如果獲取 POST 請(qǐng)求的內(nèi)容?」。懂得用搜索引擎的同學(xué)肯定可以很容易地找到這么一個(gè)答案:監(jiān)聽 data 事件收集數(shù)據(jù),在 end 事件中把收集到的數(shù)據(jù)合并起來(lái)。是的,這是解決這個(gè)問(wèn)題的方法。但是為什么它如此設(shè)計(jì)呢?像 PHP 那樣直接就可以取到 POST 內(nèi)容多好?其實(shí)這么設(shè)計(jì)是有好處的,如果我們接收到的數(shù)據(jù)是非法的,我可以馬上察覺(jué),然后響應(yīng)并斷開連接。這樣可以避免一些不必要的傳輸成本。比如上傳圖片,也許用戶錯(cuò)誤地選擇了一個(gè)很大的可執(zhí)行文件,我們不需要等到這個(gè)文件完全上傳完畢,只要一個(gè)文件頭部的若干字節(jié)就能判斷一個(gè)文件是否是圖片了。此處使用流的設(shè)計(jì)就可以先讀出前面的幾個(gè)字節(jié)來(lái)使用。
上面提到的 data 事件和 end 事件都是 Readable 的事件,這兩個(gè)事件分別表示收到數(shù)據(jù)和數(shù)據(jù)接收完畢。所以其實(shí)我們?cè)缫阎懒?Readable 的用法,只是很多人不知道它是 Readable 對(duì)象而已。
但是上面這兩個(gè)事件僅僅是對(duì) Readable 的消費(fèi)者而言的事件。內(nèi)部是如何把一個(gè)數(shù)據(jù)推送到 Readable 對(duì)象里面讓 Readable 觸發(fā)出這些事件的呢?那么它就是 push 方法。下面是一個(gè)例子,它創(chuàng)建了一個(gè) Readable 對(duì)象,這個(gè)對(duì)象會(huì)流出一個(gè)遞增的數(shù)字(這里使用了 babel-node)
import stream from 'stream';
var r = new stream.Readable;
r.on('data', data => {
console.log(data + '');
});
r.on('end', data => {
console.log('end');
});
r._read = () => {
// console.log('before read');
};
void function callee(i) {
if(i < 10) {
r.push(i + ''); // 只能傳入字符串或 Buffre 對(duì)象
} else {
r.push(null); // 當(dāng)輸入一個(gè) null 時(shí)表示流傳輸完成,觸發(fā) end 事件
}
setTimeout(callee, 500, i + 1);
}(0);
如果仔細(xì)看上面代碼就會(huì)發(fā)現(xiàn)一個(gè)很神奇的地方,這個(gè)代碼覆寫了 _read 方法,這是什么鬼?其實(shí)我也覺(jué)得這是個(gè)坑,這個(gè)私有命名風(fēng)格就不吐槽了,為何非要覆寫這個(gè)方法才算實(shí)現(xiàn)它?如果沒(méi)有覆寫這個(gè)方法,那么在調(diào)用 push 時(shí)將拋出異常:
Error: not implemented at Readable._read (_stream_readable.js:464:22) at Readable.read (_stream_readable.js:341:10)
以上這些便是 Readable 對(duì)象的基本用法。但是還有更多坑會(huì)踩到,這篇文章只是一個(gè)最簡(jiǎn)單的介紹,讓大家學(xué)會(huì)如何造出一個(gè)能輸出數(shù)據(jù)的 Readable 對(duì)象而已。至于一些 read 之類的基本方法,反正這些也是不科學(xué)的設(shè)計(jì)之一。
相關(guān)文章
node.js使用免費(fèi)的阿里云ip查詢獲取ip所在地【推薦】
這篇文章主要介紹了node.js使用免費(fèi)的阿里云ip查詢獲取ip所在地的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2018-09-09
Nodejs極簡(jiǎn)入門教程(一):模塊機(jī)制
這篇文章主要介紹了Nodejs極簡(jiǎn)入門教程(一):模塊機(jī)制,本文講解了模塊基礎(chǔ)知識(shí)、模塊的加載、包等內(nèi)容,需要的朋友可以參考下2014-10-10
NodeJS 實(shí)現(xiàn)手機(jī)短信驗(yàn)證模塊阿里大于功能
這篇文章主要介紹了NodeJS 實(shí)現(xiàn)手機(jī)短信驗(yàn)證模塊阿里大于功能,需要的朋友可以參考下2017-06-06
nodejs使用Express框架寫后端接口的全過(guò)程
最近學(xué)習(xí)了基于前后端分離的開發(fā)模式,我前端使用Vue框架,后端使用nodejs開發(fā)API接口,下面這篇文章主要給大家介紹了關(guān)于nodejs使用Express框架寫后端接口的相關(guān)資料,需要的朋友可以參考下2022-05-05
使用NodeJs 開發(fā)微信公眾號(hào)(三)微信事件交互實(shí)例
這篇文章主要介紹了使用NodeJs 開發(fā)微信公眾號(hào)(三)微信事件交互實(shí)例的相關(guān)資料,需要的朋友可以參考下2016-03-03
Node.js數(shù)據(jù)流Stream之Duplex流和Transform流用法
這篇文章介紹了Node.js數(shù)據(jù)流Stream之Duplex流和Transform流的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07

