成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

深入了解Node.js中的4種 stream

本篇文章帶大家了解一下Node.js中的4種 stream,看看怎么解決爆緩沖區(qū)的“背壓”問題,有需要的朋友可以去學(xué)習(xí)了解一下~

深入了解Node.js中的4種 stream

把一個(gè)東西從 A 搬到 B 該怎么搬呢?

抬起來,移動到目的地,放下不就行了么。

那如果這個(gè)東西有一噸重呢?

那就一部分一部分的搬。

其實(shí) IO 也就是搬東西,包括網(wǎng)絡(luò)的 IO、文件的 IO,如果數(shù)據(jù)量少,那么直接傳送全部內(nèi)容就行了,但如果內(nèi)容特別多,一次性加載到內(nèi)存會崩潰,而且速度也慢,這時(shí)候就可以一部分一部分的處理,這就是流的思想?!就扑]學(xué)習(xí):《nodejs 教程》】

各種語言基本都實(shí)現(xiàn)了 stream 的 api,Node.js 也是,stream api 是比較常用的,下面我們就來探究一下 stream。

本文會回答以下問題:

  • Node.js 的 4 種 stream 是什么
  • 生成器如何與 Readable Stream 結(jié)合
  • stream 的暫停和流動
  • 什么是背壓問題,如何解決

Node.js 的 4種 stream

流的直觀感受

從一個(gè)地方流到另一個(gè)地方,顯然有流出的一方和流入的一方,流出的一方就是可讀流(readable),而流入的一方就是可寫流(writable)。

深入了解Node.js中的4種 stream

當(dāng)然,也有的流既可以流入又可以流出,這種叫做雙工流(duplex)

深入了解Node.js中的4種 stream

既然可以流入又可以流出,那么是不是可以對流入的內(nèi)容做下轉(zhuǎn)換再流出呢,這種流叫做轉(zhuǎn)換流(transform)

深入了解Node.js中的4種 stream

duplex 流的流入和流出內(nèi)容不需要相關(guān),而 transform 流的流入和流出是相關(guān)的,這是兩者的區(qū)別。

流的 api

Node.js 提供的 stream 就是上面介紹的那 4 種:

const stream = require('stream');  // 可讀流 const Readable = stream.Readable; // 可寫流 const Writable = stream.Writable; // 雙工流 const Duplex = stream.Duplex; // 轉(zhuǎn)換流 const Transform = stream.Transform;

它們都有要實(shí)現(xiàn)的方法:

  • Readable 需要實(shí)現(xiàn) _read 方法來返回內(nèi)容
  • Writable 需要實(shí)現(xiàn) _write 方法來接受內(nèi)容
  • Duplex 需要實(shí)現(xiàn) _read 和 _write 方法來接受和返回內(nèi)容
  • Transform 需要實(shí)現(xiàn) _transform 方法來把接受的內(nèi)容轉(zhuǎn)換之后返回

我們分別來看一下:

Readable

Readable 要實(shí)現(xiàn) _read 方法,通過 push 返回具體的數(shù)據(jù)。

const Stream = require('stream');  const readableStream = Stream.Readable();  readableStream._read = function() {     this.push('阿門阿前一棵葡萄樹,');     this.push('阿東阿東綠的剛發(fā)芽,');     this.push('阿東背著那重重的的殼呀,');     this.push('一步一步地往上爬。')     this.push(null); }  readableStream.on('data', (data)=> {     console.log(data.toString()) });  readableStream.on('end', () => {     console.log('done~'); });

當(dāng) push 一個(gè) null 時(shí),就代表結(jié)束流。

執(zhí)行效果如下:

深入了解Node.js中的4種 stream

創(chuàng)建 Readable 也可以通過繼承的方式:

const Stream = require('stream');  class ReadableDong extends Stream.Readable {      constructor() {         super();     }      _read() {         this.push('阿門阿前一棵葡萄樹,');         this.push('阿東阿東綠的剛發(fā)芽,');         this.push('阿東背著那重重的的殼呀,');         this.push('一步一步地往上爬。')         this.push(null);     }  }  const readableStream = new ReadableDong();  readableStream.on('data', (data)=> {     console.log(data.toString()) });  readableStream.on('end', () => {     console.log('done~'); });

可讀流是生成內(nèi)容的,那么很自然可以和生成器結(jié)合:

const Stream = require('stream');  class ReadableDong extends Stream.Readable {      constructor(iterator) {         super();         this.iterator = iterator;     }      _read() {         const next = this.iterator.next();         if(next.done) {             return this.push(null);         } else {             this.push(next.value)         }     }  }  function *songGenerator() {     yield '阿門阿前一棵葡萄樹,';     yield '阿東阿東綠的剛發(fā)芽,';     yield '阿東背著那重重的的殼呀,';     yield '一步一步地往上爬。'; }  const songIterator = songGenerator();  const readableStream = new ReadableDong(songIterator);  readableStream.on('data', (data)=> {     console.log(data.toString()) });  readableStream.on('end', () => {     console.log('done~'); });

這就是可讀流,通過實(shí)現(xiàn) _read 方法來返回內(nèi)容。

Writable

Writable 要實(shí)現(xiàn) _write 方法,接收寫入的內(nèi)容。

const Stream = require('stream');  const writableStream = Stream.Writable();  writableStream._write = function (data, enc, next) {    console.log(data.toString());    // 每秒寫一次    setTimeout(() => {        next();    }, 1000); }  writableStream.on('finish', () => console.log('done~'));  writableStream.write('阿門阿前一棵葡萄樹,'); writableStream.write('阿東阿東綠的剛發(fā)芽,'); writableStream.write('阿東背著那重重的的殼呀,'); writableStream.write('一步一步地往上爬。'); writableStream.end();

接收寫入的內(nèi)容,打印出來,并且調(diào)用 next 來處理下一個(gè)寫入的內(nèi)容,這里調(diào)用 next 是異步的,可以控制頻率。

跑了一下,確實(shí)可以正常的處理寫入的內(nèi)容:

深入了解Node.js中的4種 stream

這就是可寫流,通過實(shí)現(xiàn) _write 方法來處理寫入的內(nèi)容。

Duplex

Duplex 是可讀可寫,同時(shí)實(shí)現(xiàn) _read 和 _write 就可以了

const Stream = require('stream');  var duplexStream = Stream.Duplex();  duplexStream._read = function () {     this.push('阿門阿前一棵葡萄樹,');     this.push('阿東阿東綠的剛發(fā)芽,');     this.push('阿東背著那重重的的殼呀,');     this.push('一步一步地往上爬。')     this.push(null); }  duplexStream._write = function (data, enc, next) {     console.log(data.toString());     next(); }  duplexStream.on('data', data => console.log(data.toString())); duplexStream.on('end', data => console.log('read done~'));  duplexStream.write('阿門阿前一棵葡萄樹,'); duplexStream.write('阿東阿東綠的剛發(fā)芽,'); duplexStream.write('阿東背著那重重的的殼呀,'); duplexStream.write('一步一步地往上爬。'); duplexStream.end();  duplexStream.on('finish', data => console.log('write done~'));

整合了 Readable 流和 Writable 流的功能,這就是雙工流 Duplex。

深入了解Node.js中的4種 stream

Transform

Duplex 流雖然可讀可寫,但是兩者之間沒啥關(guān)聯(lián),而有的時(shí)候需要對流入的內(nèi)容做轉(zhuǎn)換之后流出,這時(shí)候就需要轉(zhuǎn)換流 Transform。

Transform 流要實(shí)現(xiàn) _transform 的 api,我們實(shí)現(xiàn)下對內(nèi)容做反轉(zhuǎn)的轉(zhuǎn)換流:

const Stream = require('stream');  class TransformReverse extends Stream.Transform {    constructor() {     super()   }    _transform(buf, enc, next) {     const res = buf.toString().split('').reverse().join('');     this.push(res)     next()   } }  var transformStream = new TransformReverse();  transformStream.on('data', data => console.log(data.toString())) transformStream.on('end', data => console.log('read done~'));  transformStream.write('阿門阿前一棵葡萄樹'); transformStream.write('阿東阿東綠的剛發(fā)芽'); transformStream.write('阿東背著那重重的的殼呀'); transformStream.write('一步一步地往上爬'); transformStream.end()  transformStream.on('finish', data => console.log('write done~'));

跑了一下,效果如下:

深入了解Node.js中的4種 stream

流的暫停和流動

我們從 Readable 流中獲取內(nèi)容,然后流入 Writable 流,兩邊分別做 _read 和 _write 的實(shí)現(xiàn),就實(shí)現(xiàn)了流動。

深入了解Node.js中的4種 stream

背壓

但是 read 和 write 都是異步的,如果兩者速率不一致呢?

如果 Readable 讀入數(shù)據(jù)的速率大于 Writable 寫入速度的速率,這樣就會積累一些數(shù)據(jù)在緩沖區(qū),如果緩沖的數(shù)據(jù)過多,就會爆掉,會丟失數(shù)據(jù)。

而如果 Readable 讀入數(shù)據(jù)的速率小于 Writable 寫入速度的速率呢?那沒關(guān)系,最多就是中間有段空閑時(shí)期。

這種讀入速率大于寫入速率的現(xiàn)象叫做“背壓”,或者“負(fù)壓”。也很好理解,寫入段壓力比較大,寫不進(jìn)去了,會爆緩沖區(qū),導(dǎo)致數(shù)據(jù)丟失。

這個(gè)緩沖區(qū)大小可以通過 readableHighWaterMark 和 writableHightWaterMark 來查看,是 16k。

深入了解Node.js中的4種 stream

解決背壓

怎么解決這種讀寫速率不一致的問題呢?

當(dāng)沒寫完的時(shí)候,暫停讀就行了。這樣就不會讀入的數(shù)據(jù)越來越多,駐留在緩沖區(qū)。

readable stream 有個(gè) readableFlowing 的屬性,代表是否自動讀入數(shù)據(jù),默認(rèn)為 true,也就是自動讀入數(shù)據(jù),然后監(jiān)聽 data 事件就可以拿到了。

當(dāng) readableFlowing 設(shè)置為 false 就不會自動讀了,需要手動通過 read 來讀入。

readableStream.readableFlowing = false;  let data; while((data = readableStream.read()) != null) {     console.log(data.toString()); }

但自己手動 read 比較麻煩,我們依然可以用自動流入的方式,調(diào)用 pause 和 resume 來暫停和恢復(fù)就行了。

當(dāng)調(diào)用 writable stream 的 write 方法的時(shí)候會返回一個(gè) boolean 值代表是寫入了目標(biāo)還是放在了緩沖區(qū):

  • true: 數(shù)據(jù)已經(jīng)寫入目標(biāo)
  • false:目標(biāo)不可寫入,暫時(shí)放在緩沖區(qū)

我們可以判斷返回 false 的時(shí)候就 pause,然后等緩沖區(qū)清空了就 resume:

const rs = fs.createReadStream(src); const ws = fs.createWriteStream(dst);  rs.on('data', function (chunk) {     if (ws.write(chunk) === false) {         rs.pause();     } });  rs.on('end', function () {     ws.end(); });  ws.on('drain', function () {     rs.resume(); });

這樣就能達(dá)到根據(jù)寫入速率暫停和恢復(fù)讀入速率的功能,解決了背壓問題。

pipe 有背壓問題么?

平時(shí)我們經(jīng)常會用 pipe 來直接把 Readable 流對接到 Writable 流,但是好像也沒遇到過背壓問題,其實(shí)是 pipe 內(nèi)部已經(jīng)做了讀入速率的動態(tài)調(diào)節(jié)了。

const rs = fs.createReadStream(src); const ws = fs.createWriteStream(dst);  rs.pipe(ws);

總結(jié)

流是傳輸數(shù)據(jù)時(shí)常見的思想,就是一部分一部分的傳輸內(nèi)容,是文件讀寫、網(wǎng)絡(luò)通信的基礎(chǔ)概念。

Node.js 也提供了 stream 的 api,包括 Readable 可讀流、Writable 可寫流、Duplex 雙工流、Transform 轉(zhuǎn)換流。它們分別實(shí)現(xiàn) _read、_write、_read + _write、_transform 方法,來做數(shù)據(jù)的返回和處理。

創(chuàng)建 Readable 對象既可以直接調(diào)用 Readable api 創(chuàng)建,然后重寫 _read 方法,也可以繼承 Readable 實(shí)現(xiàn)一個(gè)子類,之后實(shí)例化。其他流同理。(Readable 可以很容易的和 generator 結(jié)合)

當(dāng)讀入的速率大于寫入速率的時(shí)候就會出現(xiàn)“背壓”現(xiàn)象,會爆緩沖區(qū)導(dǎo)致數(shù)據(jù)丟失,解決的方式是根據(jù) write 的速率來動態(tài) pause 和 resume 可讀流的速率。pipe 就沒有這個(gè)問題,因?yàn)閮?nèi)部做了處理。

流是掌握 IO 繞不過去的一個(gè)概念,而背壓問題也是流很常見的問題,遇到了數(shù)據(jù)丟失可以考慮是否發(fā)生了背壓。希望這篇文章能夠幫大家理清思路,真正掌握 stream!

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
久激情内射婷内射蜜桃人妖| 18级成人毛片免费观看| 亚洲愉拍自拍欧美精品| 亚洲乱码日产精品M| 夜先锋AV资源网站| 99精品无人区乱码1区2区3区| JULIA无码中文字幕一区| 错位关系C1V1一块五花肉| 国产护士在线视频XXXX免费| 国语自产第1国语自产第10页| 久久国产精品成人影院| 女人两腿扒开图片大全| 日韩电影久久久被窝网| 国产精品亚洲А∨无码播放| 2021影音先锋AⅤ资源男人网| А√最新版在线天堂| 丰满人妻被黑人连续中出| 国产亚洲精品精华液好用吗| 久久久久久精品免费久久18| 欧美V日韩V亚洲V最新在线观看| 日本工口里番H彩色无遮挡全彩 | 欧美兽交YOYO| 人妻中文字幕制服丝袜| 无人区免费一二三四乱码| 亚洲欧洲精品成人久久曰影片| 97国产精华最好的产品亚洲| 大香伊蕉在人线国产最新75| 国内少妇偷人精品免费| 老司机久久99久久精品播放| 日本熟妇色XXXXX日本妇奷| 性欧美ⅩXXXX极品少妇小说| 正在播放强揉爆乳女教师| 从厨房一路干到卧室好吗| 黑人上司粗大拔不出来电影| 欧美成性视頻XXXⅩXXX| 武则天裸毛片70分钟| 在线亚洲熟妇一区二区三| 丰满少妇女人A毛片视频| 久久99精品久久久久久青青| 人妻少妇精品专区性色AV| 亚洲AV无码成人精品区天堂 | 亚洲A级成人无码网站| 人妻无码第一区二区三区| 久久久精品成人免费观看国产 | А√ 天堂 在线官网中文| 国产亚洲精品A在线观看| 女孩子手脚绑起来嘴用胶带封上| 婷婷五月综合色中文字幕| 在厨房乱子伦对白| 国产精品盗摄!偷窥盗摄| 老阿姨哔哩哔哩B站肉片茄子芒果| 揉着我的奶从后面进去| 亚洲综合久久成人AV| 国产AⅤ精品福利一区二区三区| 久久婷婷色综合老司机| 四十路の五十路熟女豊満AV| 伊人婷婷六月狠狠狠去| 国产精品福利一区二区久久| 妺妺窝人体色WWW在线一| 性欧美大战久久久久久久久| YSL千人千色T9T9T9T| 精品人无码一区二区三区| 日韩精品无码一区二区三区四区 | 我把英语课代表按在桌子上抄| 中文字幕人妻成人综合永久 | 动漫精品啪啪一区二区三区| 久久精品99国产精品日本| 三上悠亚AV资源站| 中国少妇的BBWWBBWW| 小雪被老外黑人撑破了视频| 亚洲成AV人片在线观看不卡| 丁香狠狠色婷婷久久综合| 绿帽娇妻在卧室疯狂的呻吟| 西方137大但人文艺术| 爱丫爱丫影院电影网| 久久99精品国产自在现线小黄鸭| 丝袜灬啊灬快灬高潮了AV| AAA级久久久精品无码片| 精品久久久久久无码专区| 太太其实你也很想要的对吧| BT天堂网WWW天堂在线资源| 久久WWW免费人成_网站| 无码 制服 丝袜 国产 另类| WWW无套内射高清免费| 久久人妻少妇嫩草AV蜜桃| 性无码一区二区三区在线观看| 成人特黄A级毛片免费视频| 美女下部裸体张开腿视频| 亚洲国产一二三精品无码| 国产精品高潮呻吟久久AV| 日本打扑克啪啪超爽网站| 中国熟妇毛多多裸交视频| 精品久久人人做人人爽综合| 香蕉网久久久久丫| 公交车上摸到花蒂进去了视频| 人妻少妇精品久久久久久0000| 中文字幕一精品亚洲无线一区| 久久精品道一区二区三区| 亚洲AV嫩草AV极品在线观看| 国产成人无码精品一区不卡| 日韩v亚洲v欧美v精品综合| 97精品依人久久久大香线蕉97| 久久久久99精品成人片牛牛影视| 亚洲AV成人无码天堂| 国产成人亚洲综合色影视| 人人妻人人爽日日人人| 日本AⅤ精品一区二区三区久久| 中文字幕日本人妻久久久免费| 久久 国产 尿 小便 嘘嘘| 亚洲成AV人片一区二区密柚| 小13箩利洗澡无码免费视频| 亚洲人成网站在线播放2020| 黑人男女粗大猛烈进出视频| 新JAPANESEVIDEO乱| 国产成人精品亚洲精品| 色多多WWW视频在线观看免费| 宝贝腿开大一点你真湿H| 欧美精品人人做人人爱视频| 1000部无遮挡拍拍拍免费视频| 老色鬼久久亚洲AV综合| 野花日本视频免费观看3| 久久国产乱子伦免费精品无码| 亚洲美女又黄又爽在线观看 | 性XXXXBBBB农村小树林| 国产精品久久久久久无码| 天堂久久久久VA久久久久| 国产97在线 | 日韩| 四川丰满少妇A级毛片| 国产成人精品白浆久久69| 天天爱天天做天天爽| 国产精品国产精品国产专区不卡| 玩小雪跪趴把腿分到最大影视频| 国产精品久久久久这里只有精品| 无码一区二区三区AV免费| 国产熟妇XXXXXⅩ性Ⅹ交| 亚洲AV无码成人精品区H| 激情内射亚洲一区二区三区爱妻| 亚洲精品乱码久久久久66| 久久精品国产999久久久| 婬乱丰满熟妇XXXXX性| 蜜臀av一区二区蜜臀AV免费| ASS年轻少妇BBWPIC精品| 強暴強姦AV正片一区二区三区| 成熟丰满熟妇高潮XXXX| 天堂А√在线地址资源| 国产人成高清在线视频99最全资| 亚洲AV无码一区二区二三区3p| 精品欧美成人高清在线观看| 一女大战七个黑人到喷浆| 你真紧你这是要我的命吗| 扒开校花的粉嫩小泬| 少妇爆乳无码AV专区网站寝取| 国产精品成人观看视频国产奇米| 亚洲AV成人一区二区三区AV| 久久狠狠色噜噜狠狠狠狠97| 中文字幕人妻三级中文无码视频| 人妻AV中文系列| 国产成人无码午夜视频在线观看| 无码少妇一区二区浪潮免费| 精品国产一区二区三区AV性色 | 波多野结衣AV一区二区无码| 婷婷久久综合九色综合97最多收 | 亚洲AV无码专区亚洲AV| 久久久99精品成人片中文字幕| 中文无码日韩欧免费视频APP | 美女扒开腿让男人桶爽30分钟| 宝宝锕~进去就不痛了在线观看| 铜铜铜铜铜铜铜铜好痛好深色板| 激情欧美日韩一区二区| 中文字幕乱近親相姦| 欧亚尺码专线欧洲B1B1| 东京热无码AV男人的天堂| 色悠久久久久久久综合网| 国产剧情AV麻豆香蕉精品| 无遮挡边吃奶边做的视频刺激| 极品教师动漫在线观看免费完整版| 在教室伦流澡到高潮HGL视频| おまえの母亲をだます怎么读| 男朋友一晚弄了我5次正常吗| JΑPΑN丰满人妻HDXXXX| 日韩系列 无码迅雷| 国产精品美女久久久久网站浪潮 | 免费少妇A级毛片人成网| エロドラえもんCOM中文在线| 欧洲精品99毛片免费高清观看| 被村长狂躁俩小时玉婷| 婷婷综合久久中文字幕| 狠狠色婷婷久久一区二区| 东京热加勒比无码少妇| 亚洲AV成人无码一二三在线观看 | 99久久人妻精品免费二区| 少妇高潮喷水久久久久久久久久 | 久久精品人人做人人爽电影| 曰韩一区二区三区视频| 热99RE久久国超精品首页| 国产精品特级露脸AV毛片| 麻豆一区二区三区蜜桃免费| 日本一线二线三线四线五线| 秋霞国产成人精品午夜视频APP| 免费高清视频 大片|