首頁  >  文章  >  web前端  >  淺談Nodejs中的雙工流

淺談Nodejs中的雙工流

青灯夜游
青灯夜游轉載
2020-11-23 17:52:343996瀏覽

淺談Nodejs中的雙工流

相關推薦:《node js教學

#雙工流就是同時實作了Readable 和Writable 的串流,也就是可以作為上游生產數據,又可以作為下游消費數據,這樣可以處於數據流動管道的中間部分,即

 rs.pipe(rws1).pipe(rws2).pipe(rws3).pipe(ws);

在NodeJS 中雙工流常用的有兩種

  • Duplex

  • Transform

#Duplex

實作Duplex

和Readable、Writable 實作方法類似,實作Duplex 流非常簡單,但Duplex 同時實作了Readable 和Writable, NodeJS 不支援多繼承,所以我們需要繼承Duplex 類別

  • 繼承Duplex 類別

  • 實作_read() 方法

  • 實作_write() 方法

##相信大家對

read()、write() 方法的實作不會陌生,因為和Readable、Writable 完全一樣。

const Duplex = require('stream').Duplex;

const myDuplex = new Duplex({
  read(size) {
    // ...
  },
  write(chunk, encoding, callback) {
    // ...
  }
});

建構子參數

Duplex 實例內同時包含可讀流和可寫流,在實例化Duplex 類別的時候可以傳遞幾個參數

    readableObjectMode
  • : 可讀流是否設定為ObjectMode,預設為false
  • writableObjectMode
  • : 可寫流是否設定為ObjectMode,預設為false
  • #allowHalfOpen
  • : 預設true, 設定成false 的話,當寫入端結束的時,流會自動的結束讀取端,反之亦然。

小範例

了解了Readable 和Writable 之後看Duplex 很簡單,直接用一個官網的例子

 const Duplex = require('stream').Duplex;
const kSource = Symbol('source');

class MyDuplex extends Duplex {
  constructor(source, options) {
    super(options);
    this[kSource] = source;
  }

  _write(chunk, encoding, callback) {
    // The underlying source only deals with strings
    if (Buffer.isBuffer(chunk))
      chunk = chunk.toString();
    this[kSource].writeSomeData(chunk);
    callback();
  }

  _read(size) {
    this[kSource].fetchSomeData(size, (data, encoding) => {
      this.push(Buffer.from(data, encoding));
    });
  }
}
當然這是不能執行的偽代碼,但是Duplex 的作用可見一斑,進可以生產數據,又可以消費數據,所以才可以處於數據流動管道的中間環節,常見的Duplex 流有

    Tcp Scoket
  • Zlib
  • Crypto
#Transform

Transform 同樣是雙工流,看起來和Duplex 重複了,但兩者有一個重要的區別:Duplex 雖然同事具備可讀流和可寫流,但兩者是相對獨立的;Transform 的可讀流的資料會經過一定的處理過程自動進入可寫流。

雖然會從可讀流進入可寫流,但這並不意味著這兩者的資料量相同,上面所說的一定的處理邏輯會決定如果tranform 可讀流,然後放入可寫流,transform 原義即為轉變,很貼切的描述了Transform 流作用。

我們最常見的壓縮、解壓縮用的 zlib 即為 Transform 流,壓縮、解壓縮前後的資料量明顯不同,兒流的作用就是輸入一個 zip 包,輸入一個解壓縮檔或反過來。我們平常用的雙工流大多是 Transform。

實作Tranform

Tranform 類別內部繼承了Duplex 並實作了writable.write() 和readable._read() 方法,我們想自訂一個Transform 流,只需要

  • 繼承Transform 類別

  • ##transform() 方法

  • ##實作_flush () 方法(可以不實作)
  • _transform(chunk, encoding, callback) 方法用來接收數據,並產生輸出,參數我們已經很熟悉了,和Writable 一樣, chunk預設是Buffer,除非decodeStrings 被設定為false。

在 _transform() 方法內部可以調用 this.push(data) 生產數據,交給可寫流,也可以不調用,意味著輸入不會產生輸出。

當資料處理完了必須呼叫callback(err, data)  ,第一個參數用來傳遞錯誤訊息,第二個參數可以省略,如果被傳入了,效果和this.push(data)一樣

 transform.prototype._transform = function (data, encoding, callback) {
  this.push(data);
  callback();
};

transform.prototype._transform = function (data, encoding, callback) {
  callback(null, data);
};

有些時候,transform 操作可能需要在流的最後多寫入可寫流一些資料。例如, Zlib流會儲存一些內部狀態,以便最佳化壓縮輸出。在這種情況下,可以使用_flush()方法,它會在所有寫入資料被消費、觸發 'end'之前被呼叫。

Transform 事件

Transform 流有兩個常用的事件

    #來自Writable 的finish
  • 來自Readable 的end
  • 當呼叫transform.end() 且資料被_transform() 處理完後會觸發finish,呼叫_flush後,所有的資料輸出完畢,觸發end事件。

對比

了解了Readable 和Writable 之後,理解雙工流十分自然,但兩者的區別會讓一些初學者困惑,簡單的區分:Duplex 的可讀流和可寫入流之間並沒有直接關係,Transform 中可讀流的資料會經過處理後自動放入可寫流中。

看兩個簡單的例子就能直觀了解 Duplex 和 Transform 的差異

TCP socket

net 模块可以用来创建 socket,socket 在 NodeJS 中是一个典型的 Duplex,看一个 TCP 客户端的例子

var net = require('net');

//创建客户端
var client = net.connect({port: 1234}, function() {
    console.log('已连接到服务器');
    client.write('Hi!');
});

//data事件监听。收到数据后,断开连接
client.on('data', function(data) {
    console.log(data.toString());
    client.end();
});

//end事件监听,断开连接时会被触发
client.on('end', function() {
    console.log('已与服务器断开连接');
});

可以看到 client 就是一个 Duplex,可写流用于向服务器发送消息,可读流用于接受服务器消息,两个流内的数据并没有直接的关系。

gulp

gulp 非常擅长处理代码本地构建流程,看一段官网的示例代码

gulp.src('client/templates/*.jade')
  .pipe(jade())
  .pipe(minify())
  .pipe(gulp.dest('build/minified_templates'));

其中 jada() 和 minify() 就是典型的 Transform,处理流程大概是

.jade 模板文件 -> jada() -> html 文件 -> minify -> 压缩后的 html

可以看出来,jade() 和 minify() 都是对输入数据做了些特殊处理,然后交给了输出数据。

这样简单的对比就能看出 Duplex 和 Transform 的区别,在平时实用的时候,当一个流同事面向生产者和消费者服务的时候我们会选择 Duplex,当只是对数据做一些转换工作的时候我们便会选择使用 Tranform。

更多编程相关知识,请访问:编程学习网站!!

以上是淺談Nodejs中的雙工流的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除