簡體   English   中英

節點雙工流在讀取時實際上不會發出數據

[英]Node duplex stream doesn't actually emit data when read

我正在研究最終將用於 nodejs 中的鍵值對象流的各種數據接收器。

我偶然發現了雙工流並開始嘗試使用它們來弄濕我的腳,但我嘗試的一切似乎都不起作用。

目前,我有這個雙工流:

class StorageStream extends stream.Duplex {
  constructor() {
    super({
      objectMode: true
    })

    this.values = new Map();
    this.entries = this.values.entries();
  }

  _write(data, encoding, next) {
    const { key, value } = data;

    this.values.set(key, value);

    next();
  }

  _read() {
    const next = this.entries.next();

    if (next.value) {
      this.push(next.value);
    }
  }
}

這是一個超級設計的例子,但本質上,當我寫入這個流時,它應該將鍵和值存儲在地圖中,當我從這個流中讀取時,它應該開始從地圖讀取並將它們傳遞到流中。 但是,這不起作用,基本上執行以下操作

const kvstream = createKVStreamSomeHow(); // a basic, readable stream with KV Pairs

const logger = createLoggerStreamSomeHow(); // writable stream, logs the data coming through

const storage = new StorageStream();

kvstream.pipe(storage).pipe(logger);

導致進程剛剛結束。 所以我想我對我應該在_read方法中做什么感到有點困惑。

OP提供的代碼的一些觀察:

  1. 遍歷read()返回的鍵的迭代器是在設置任何鍵之前生成的,在: this.entries = this.values.entries(); . 因此,調用 read() 永遠不會產生輸出。
  2. 如果在 Map 中設置了新鍵,則不會將其推送到讀取緩沖區以供后續可寫處理

可以使用內置的Transform (docs)構造函數簡化雙工實現。 轉換構造函數非常適合存儲轉發場景。

這是如何在這種情況下應用流轉換的示例。 請注意, pipeline()函數不是必需的,並且已在此示例中用於簡化等待可讀對象發出其所有數據的過程:

const { Writable, Readable, Transform, pipeline } = require('stream');

class StorageStream extends Transform {
  constructor() {
    super({
      objectMode: true
    })

    this.values = new Map();
  }

  _transform(data, encoding, next) {
    const { key, value } = data;

    this.values.set(key, value);
    console.log(`Setting Map key ${key} := ${value}`)

    next(null, data);
  }
}

(async ()=>{
  await new Promise( resolve => {
    pipeline(
      new Readable({
        objectMode: true,
        read(){
          this.push( { key: 'foo', value: 'bar' } );
          this.push( null );
        }
      }),
      new StorageStream(),
      new Writable({
        objectMode: true,
        write( chunk, encoding, next ){
          console.log("propagated:", chunk);
          next();
        }
      }),
      (error) => {
        if( error ){
          reject( error );
        }
        else {
          resolve();
        }
      }
    );
  });
})()
  .catch( console.error );

這會產生以下輸出

> Setting Map key foo := bar
> propagated: { key: 'foo', value: 'bar' }

並且可以用作

kvstream.pipe(new StorageStream()).pipe(logger);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM