亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入探究node之Transform

2019-11-19 16:02:10
字體:
來源:轉載
供稿:網友

本文詳細的介紹了node Transform ,分享給大家,希望此文章對各位有所幫助。

Transform流特性

在開發中直接接觸Transform流的情況不是很多,往往是使用相對成熟的模塊或者封裝的API來完成流的處理,最為特殊的莫過于through2模塊和gulp流操作。那么,Transform流到底有什么特點呢?

從名稱上說,Transform意為處理,類似于生產流水線上的每一道工序,每道工序針對到來的產品作相應的處理;從結構上看,Transform是一個雙工流,通俗的解釋它既可以作為可讀流,也可作為可寫流。但是,node卻對Transform流針對其特性做了更為特殊的定制,使Transform不是單純的Duplex流。

Transform流由于包含了Readable和Writeable特性,因此Transform在實際使用中有著多種方式:它既可以只作為消費者消費數據,也可同時作為生產者和消費者完成數據中間處理。下面將逐漸深入內部闡述Transform的運行機理及使用技巧。

Transform內部架構

上圖表示一個Transform實例的組成部分:Readable部分緩沖(數組)、內部_read函數、Writeable部分緩沖(鏈表)、內部_write函數、Transform實例必須實現的內部_transform函數以及系統提供的回調函數afterTransform。由于Transform實例同時擁有兩部分緩沖,因此2個緩沖的存儲、消耗的順序也就需要了解,這對于后面使用原生Transform編寫代碼有很大的指導意義。

傳統意義的流(即Readable和Writeable)的實現者都需要實現對應的內部函數_read()和_write(),對于Readable實例而言,_read函數用于準備從源文件中獲取數據并添加到讀緩沖中;對于Writeable實例_write函數則從寫緩沖鏈表中一次刷入到磁盤中。它們分別對應了讀寫流程的首尾步驟,具體可以關注node中的Stream一文。

而Transform中的_read和_write函數的實現大有不同,由于需要兼顧流的處理,因此著重分析Transform的內部函數執行流程。

示例demo:

readable.pipe(transform);

以上段示例代碼為例,transform作為消費者消費readable。

Transform的實例transform擁有transormState和readableState屬性,保存了相關屬性,如tranform狀態信息、回調函數存儲和編碼等。transform作為消費者,會在其write函數中消費數據,在node中的Stream文中介紹了write函數的實現細節,通過內部調用_write函數實現數據的寫入。而在Transform中_write函數已經重寫:

1.保存transform收到的chunk數據、編碼和函數(執行刷新寫緩沖)

2.在一定條件下執行_read函數(當狀態為非轉換下,只要讀緩沖大小未超過設定的大小,則執行_read)

如果一切順利,readable的數據會順利執行transform的**write->_write->_read**,那么原本負責填充讀緩沖的_read在Transform中發生了哪些改變呢?

Transform.prototype._read = function(n) { var ts = this._transformState; if (ts.writechunk !== null && ts.writecb && !ts.transforming) {  ts.transforming = true;  this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); } else {  // mark that we need a transform, so that any data that comes in  // will get processed, now that we've asked for it.  ts.needTransform = true; }};

可見,_read的實現非常簡單,根據條件選擇執行_transform函數。需要注意的是_read的參數n并未有使用,因為是否插入數據至讀緩沖是由開發者在_transform中來決定。相信大家對_transform函數并不陌生,node規定Transform實例必須提供_transform函數,而該函數正是在_read中調用。

_transform有三個參數,第一個為待處理的chunk數據,第二個為編碼,第三個為回調函數。前兩個參數很好理解,我們可以在_transform中盡情的處理數據,最后調用回調函數完成處理。那么,這個回調函數究竟是什么? 它就是Transform架構圖中的afterTransform函數,它有幾個功能:

1.清空各種狀態信息,如transformState對象的一些屬性,用于下次處理數據使用

2.可選的保存處理結果至讀緩沖區

3.刷新寫緩沖區,執行下一階段的數據流處理

可見,在afterTransform函數執行后,才基本宣告transform第一階段的結束。為何是第一階段呢?因為transform才完成了作為消費者(即Writeable)的作用,如果用戶在_transform中傳入了數據到寫緩沖區,那么此時transform也同時是一個生產者,提供數據讓后面的消費者消費數據,這就涉及到了Transform使用上的問題。

Transform的生產消費實例

const stream = require('stream')var c = 0;const readable = stream.Readable({ highWaterMark: 2, read: function () {  var data = c < 26 ? String.fromCharCode(c++ + 97) : null;  console.log('push', data);  this.push(data);}})const transform = stream.Transform({ highWaterMark: 2, transform: function (buf, enc, next) {  console.log('transform', buf.toString());  next(null, buf); }})readable.pipe(transform);

示例代碼很簡單,創建了一個可讀流,向消費者提供a-z的小寫字母;創建了一個轉換流,在_transform函數中針對數據并不做處理僅作打點輸出,并向回調函數傳遞數據至讀緩沖區。我們的目的是通過transform輸出26個小寫字母,但是當前程序執行的結果并不讓人滿意:

執行結果:
push a
push b
transform a
push c
transform b
push d
push e
push f

tranform僅僅處理到字母b,readable也僅僅提供了a-f的數據便戛然而止,這是為何?

這一切都歸結于transform對象。認真讀過上文后我們知道,所有的Transform實例同時有兩個緩沖區,其中寫緩沖區用來接收生產者的數據進行轉換操作,讀緩沖區則緩存數據給消費者使用。而在當前的實現中,transform._transform函數輸出了待處理數據,同時執行next(null, buf);。該函數上文已有分析,即afterTransform函數,第一個參數為Error實例,第二個則為存入讀緩沖區的數據。在本例中,執行完_transform后將處理后的數據存入讀緩沖區,等待后面的消費者消費讀緩沖區的數據??墒牵瑃ransform后面沒有消費者了,因此transform在處理完字母b存入讀緩沖區后,讀緩沖區已經滿了(設定highWaterMark為2,即讀寫緩沖區的最大值均為2字節)。當字母c、d也執行到tranform._write后,由于不滿足執行transform._read的條件無法執行transform._transform函數,更無法執行afterTransform函數,導致無法刷新寫緩沖區的數據,造成字母c、d貯存在寫緩沖區。而字母e、f則由于transform的寫緩沖區滿(transform.write()返回false),只有存儲在readable的讀緩沖區中,等待消費。這就造成了死循環,readable和transform所有的緩沖區都滿了,流也就停止了。

解決這個問題的方法很簡單,有兩種不同方案:

1.transform的讀緩沖區保持為空

2.增加消費者消費transform的讀緩沖區

其實本質上都是讓transform的讀緩沖區得到消耗。

第一種方案:

保證transform的讀緩沖區為空:

const transform = stream.Transform({ highWaterMark: 2, transform: function (buf, enc, next) {  console.log('transform', buf.toString())  next(null, null) }})

只需向next函數傳入null即可,這樣transform消費完數據后即宣告數據處理結束,讀緩沖區始終為空。

第二種方案:

添加消費者:

const transform = stream.Transform({ highWaterMark: 2, transform: function (buf, enc, next) {  console.log('transform', buf.toString())  next(null, buf) }})readable.pipe(transform).pipe(process.stdout);

transform實現不變,只是添加了消費者process.stdout。這樣也同時保證了transform的讀緩沖區處于可添加狀態,也給了afterTransform函數刷新寫緩沖區的機會,開啟新的數據處理流程。

through2的實現

through2的重頭戲在于Transform流,使用through2的API可方便的創建一個Transform實例,完成數據流的處理。

function through2 (construct) { return function (options, transform, flush) {  if (typeof options == 'function') {   flush   = transform   transform = options   options  = {}  }  if (typeof transform != 'function')   transform = noop  if (typeof flush != 'function')   flush = null  return construct(options, transform, flush) }}module.exports = through2(function (options, transform, flush) { var t2 = new DestroyableTransform(options) t2._transform = transform if (flush)  t2._flush = flush return t2})

可見,through2模塊僅僅是封裝了Transform的構造函數,并封裝了更為易用的objectMode模式。之所以建議使用through2創建Transform對象,不僅僅是因為其提供了方便的API,更主要的是為了兼容性。Transform對象是屬于Stream2.0的特性,早先版本的node并沒有實現,而通過through2創建的Transform實例在之前版本的node下仍可正常使用,這是由于through2并未引用node默認提供的stream模塊,而是使用社區中較為流行的“readable-stream”模塊。

總結

本文旨在深入through2中的使用的Transform流進行探究,并作為上一篇文章node中的stream的回顧和應用。通過文末簡單的示例了解Transform在開發中可能出現的問題,學會隨意切換Transform的生產者和消費者的身份,更好的指導實際開發。

以上所述是小編給大家介紹的node之Transform ,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国语自产精品视频在线看一大j8| 欧美情侣性视频| 日韩在线观看免费高清| 51精品国产黑色丝袜高跟鞋| 俺去了亚洲欧美日韩| 国产精品va在线播放| 亚洲色图激情小说| 欧美激情视频给我| 欧美成年人视频| 欧美视频专区一二在线观看| 亚洲级视频在线观看免费1级| 久久精品欧美视频| 久久69精品久久久久久久电影好| 国产精品美女久久| 欧美自拍视频在线| 久久久久日韩精品久久久男男| 成人欧美在线观看| 伊人一区二区三区久久精品| 国产精品入口免费视频一| 欧美激情一区二区三区高清视频| 疯狂欧美牲乱大交777| 国内精品久久久久久影视8| 91精品视频观看| 国产欧美精品xxxx另类| 日韩精品www| 国产成人精品一区二区三区| 久久久精品视频在线观看| 久久精品久久久久电影| 久久人人看视频| 成人免费高清完整版在线观看| 国产精品自拍小视频| 国产婷婷色综合av蜜臀av| 久久精品国产96久久久香蕉| 欧美天天综合色影久久精品| 国产精品美腿一区在线看| 亚洲国产欧美久久| 亚洲精品国产福利| 国产91ⅴ在线精品免费观看| 亚洲色图17p| 欧美性猛交视频| 国产精品99久久久久久www| 亚洲精品日产aⅴ| 国产伦精品一区二区三区精品视频| 亚洲精品国精品久久99热一| 亚洲www在线观看| 高清欧美性猛交xxxx| 亚洲字幕在线观看| 久久久国产精彩视频美女艺术照福利| 亚洲高清久久久久久| 久久夜色精品亚洲噜噜国产mv| 亚州欧美日韩中文视频| 久久网福利资源网站| 国产91精品不卡视频| 亚洲欧美在线免费观看| 欧美激情在线狂野欧美精品| 一本色道久久综合亚洲精品小说| 亚洲欧美一区二区精品久久久| 国产黑人绿帽在线第一区| 成人黄色av网| 日本韩国在线不卡| 久久久久久久久久久人体| 日韩高清欧美高清| 亚洲第一网中文字幕| 国产98色在线| 欧美大片va欧美在线播放| 国产精品久久久久久久午夜| 欧美极品美女电影一区| 精品视频9999| 久久视频免费在线播放| 日韩视频在线免费| 欧美一性一乱一交一视频| 久久精品小视频| 北条麻妃久久精品| 亚洲性夜色噜噜噜7777| 亚洲影影院av| 欧美视频13p| 亚洲影视中文字幕| 成人精品一区二区三区电影黑人| 国产精品第2页| 久久99视频精品| 中文字幕一区二区三区电影| 国产欧美欧洲在线观看| 色婷婷综合久久久久中文字幕1| 成人午夜激情免费视频| 国产不卡在线观看| 激情av一区二区| 欧美日韩一区二区三区| 久久97久久97精品免视看| 久久久久久网站| 97久久伊人激情网| 性色av一区二区三区红粉影视| 亚洲日本中文字幕| 日本久久中文字幕| 国产精品免费久久久| 国产精品久久久久久久久久三级| 国产欧美在线视频| 成人精品在线观看| 亚洲色图第一页| 欧美日韩国产一中文字不卡| 欧美丝袜第一区| 日韩中文字幕第一页| 亚洲精品国产品国语在线| 国产精自产拍久久久久久蜜| 国产成人久久精品| 欧美在线视频免费播放| 日韩av在线精品| 4p变态网欧美系列| 亚洲人成网站在线播| 久久中文字幕国产| 亚洲精品自拍视频| 国产亚洲欧美日韩精品| 欧美在线视频网站| 国产精品久久久久久网站| 国产精品99导航| 久久久久久久久久久国产| 亚洲国产成人一区| 国产婷婷色综合av蜜臀av| 日韩a**站在线观看| 日韩av手机在线| 91免费视频网站| 国产精品欧美激情在线播放| 91嫩草在线视频| 国产福利精品视频| 亚洲自拍欧美另类| 成人精品在线视频| 久久999免费视频| 在线成人一区二区| 亚洲精品成人av| 日韩视频免费大全中文字幕| 亚洲美女视频网站| 日韩欧美高清视频| 久久夜色精品国产亚洲aⅴ| 精品国产老师黑色丝袜高跟鞋| 日韩成人高清在线| 全球成人中文在线| 奇米4444一区二区三区| 亚洲高清福利视频| 亚洲自拍欧美色图| 久久成人精品一区二区三区| 久久久久久69| 亚洲在线www| 日韩久久精品成人| 亚洲国产精品va| 欧美视频中文字幕在线| 国产成人精品久久| 亚洲 日韩 国产第一| 欧美成人在线免费视频| 国内精品久久久久久| 黄色91在线观看| 国产主播欧美精品| 国产综合在线视频| 亚洲人免费视频| 九九久久精品一区| 国产亚洲欧洲黄色| 日韩精品视频中文在线观看| 成人做爰www免费看视频网站| 国产suv精品一区二区三区88区| 国产精品久久久久久久久久久久久久| 国产丝袜高跟一区| 亚洲国产精品网站| 一本色道久久88精品综合| 最近免费中文字幕视频2019| 久久久精品亚洲| 欧美日韩国产中文精品字幕自在自线|