节点双工流在读取时实际上并未发出数据

时间:2019-11-28 10:44:22

标签: javascript node.js duplex node-streams

我正在研究一种数据接收器,该数据接收器最终将用于nodejs中的键值对象流。

我偶然发现了双工流,并开始与它们玩耍以弄湿自己的脚,但是我尝试的所有操作似乎都无效。

目前,我有以下双工流:

<div class="col-sm-9">
    <select [formControlName]="i" type="text" class="form-control" [ngClass]="{'error-border': isSubmitted && mealType.errors}">
        <option value="" disabled selected></option>
        <option [ngValue]="meal.id" *ngFor="let meal of filteredMealTypes">{{meal.mealType}}</option>
    </select>
</div>

这是一个SUPER CONTRIVED示例,但是从本质上讲,当我向该流写入内容时,它应该将键和值存储在Map中,而当我从该流中读取时,它应该开始从地图中读取并将它们向下传递。但是,此操作不起作用,基本上可以执行以下操作

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); 方法中应该做的事情有点困惑。

1 个答案:

答案 0 :(得分:0)

OP提供的代码中的一些观察结果:

  1. read()中设置任何键之前,会生成循环this.entries = this.values.entries();返回的键的迭代器。因此,调用read()永远不会产生输出。
  2. 如果在Map中设置了新密钥,则不会将其推送到读取缓冲区中以供后续可写操作处理

可以使用内置的Transform (docs)构造函数来简化双工实现。转换构造函数非常适合存储转发方案。

这是在这种情况下如何应用流Transform的示例。请注意,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);