注冊'data'事件為什么
這是來自「Nodejs技術(shù)?!菇涣魅阂晃蛔x者朋友提的一個問題,,如果注釋掉 req.on 事件監(jiān)聽,end 事件就收不到了,進而永遠(yuǎn)也不會執(zhí)行 res.end,請求會被一直掛著,為什么,
如果你讀到這里,也可以先思考下這個問題!
Node.js 的可讀流對象提供了兩種模式:流動模式,暫停模式,如果你使用管道 pipe 或異步迭代可能不會關(guān)注到這個問題,在它們的內(nèi)部實現(xiàn)中已經(jīng)處理好了,如果你是基于事件的 API 來處理流,可能會有這些疑問。
流動模式
流動模式下數(shù)據(jù)自動從底層系統(tǒng)獲取,并通過 EventEmitter 提供的事件接口,盡可能快的提供給應(yīng)用程序。需要注意的是所有的可讀流一開始都處于暫停模式,要切換為流動模式,可通過以下幾種方式實現(xiàn):
一:注冊 'data' 事件
為可讀流對象注冊一個 'data' 事件,傳入事件處理函數(shù),會把流切換為流動模式,在數(shù)據(jù)可用時會立即把數(shù)據(jù)塊傳送給注冊的事件處理函數(shù)。
這也是上面的疑問,為什么注釋掉 'data' 事件,請求就會一直被掛起。
req.on, 二:stream.pipe 方法
調(diào)用 pipe 方法將數(shù)據(jù)發(fā)送到可寫流。
readable.pipe
可讀流的 pipe 方法實現(xiàn)中也是注冊了 'data' 事件,一邊讀取數(shù)據(jù)一邊寫入數(shù)據(jù)至可寫流可以參見筆者之前的這篇文章 Node.js Stream 模塊 pipe 方法使用與實現(xiàn)原理分析
Readable.prototype.pipe=functionconstsrc=this,src.on,functionondataconstret=dest.write,if...src.pause,..., 三:stream.resume 方法stream.resume 將處于暫停模式的可讀流,恢復(fù)觸發(fā) 'data' 事件,切換為流動模式。
對一開始的示例做一個改造,先調(diào)用 stream.resume 用來耗盡流中的數(shù)據(jù),但此時沒有做任何的數(shù)據(jù)處理,之后會收到 end 事件。
無需注冊事件監(jiān)聽函數(shù),使用 for...await of 遍歷可讀流,寫法上也很簡單下例,因為用到**頂級 await 特性,**需要在 ES Modules 規(guī)范中使用
暫停模式
暫停模式也是流一開始時所處的模式,該模式下會觸發(fā) 'readable' 事件,表示流中有可讀取的數(shù)據(jù),我們需要不斷調(diào)用 read 方法拉取數(shù)據(jù),直到返回 null,表示緩沖區(qū)中的數(shù)據(jù)已被耗盡,在 read 返回 null 后,會再次觸發(fā) 'readable' 事件,表示仍有可讀取的數(shù)據(jù),如果此時停止 read 方法調(diào)用,同樣的請求也會被掛起。
stream.read 方法從流緩沖區(qū)拉取數(shù)據(jù),每次返回指定 size 大小的數(shù)據(jù),如果不指定 size 則返回內(nèi)部所有緩沖的數(shù)據(jù)。
背壓問題思考
以流的形式從可讀流拉取數(shù)據(jù)到可寫流,通常**從磁盤讀取數(shù)據(jù)的速度比磁盤寫入的速度是快的,如果可寫流來不及消費數(shù)據(jù)造成數(shù)據(jù)積壓會怎么樣**也是來自「Nodejs技術(shù)棧」交流群讀者朋友的疑問,可以思考下,答案可以寫在評論區(qū),感興趣的關(guān)注下「Nodejs技術(shù)?!瓜乱淮沃v解
總結(jié)
流剛開始處于暫停模式,所以注釋掉 req.on 事件監(jiān)聽,請求才會一直掛起在基于流的方式讀取文件時,之前通常使用注冊 'data' 事件處理函數(shù)的方式從可讀流中拉取數(shù)據(jù),現(xiàn)在 Node.js 支持了異步迭代,更推薦你使用 for...await of 這種方式來讀取數(shù)據(jù),代碼看起來也會更簡潔,同步編碼思維讓人也能更好的理解
聲明:本網(wǎng)轉(zhuǎn)發(fā)此文章,旨在為讀者提供更多信息資訊,所涉內(nèi)容不構(gòu)成投資、消費建議。文章事實如有疑問,請與有關(guān)方核實,文章觀點非本網(wǎng)觀點,僅供讀者參考。