我怎么能用流传递“上下文”?

时间:2016-01-29 23:06:50

标签: javascript node.js

我有一个简单的应用程序运行,通过流管道对象,如下所示:

new ReadStreamThatCreatesData()
.pipe(new TransformerStream())
.pipe(new WriteStreamThatActsOnData()

但我希望WriteStreamThatActsOnData能够访问ReadStreamThatCreatesData中的某个媒体资源,而TransformerStream无需了解该资产或能够访问它。我想要的伪代码基本上是这样的:

new ReadStreamThatCreatesData()
.storeContext((obj) => obj.property)
.pipe(new TransformerStream())
.retieveContext((obj, context) => obj.property = context)
.pipe(new WriteStreamThatActsOnData()

但考虑到溪流的性质,我真的不明白这是怎么回事。有没有人对我如何做这样的事情有任何明智的想法?

1 个答案:

答案 0 :(得分:0)

我能想到的一种方法是将ReadStreamThatCreatesData传递给一个函数,该函数将它分成两个不同的流:一个是从项中拉出的上下文属性流,另一个是流与对象的其余部分。您将第二个流传输到TransformerStream中,然后通过将两个流组合成一个的zip运算符将该输出与上下文流一起传输。然后将其发送到WriteStreamThatActsOnData。

我认为没有内置的node.js函数来执行此操作,但您可以使用其他库,例如RxJShighland

以下是高地的示例实现:

'use strict';

/*

Put this content into input.txt. Make sure there are no blank lines in the file:    

{ "secret": 1, "val": "a" }
{ "secret": 2, "val": "b" }
{ "secret": 3, "val": "c" }
{ "secret": 4, "val": "d" }
{ "secret": 5, "val": "e" }

After running, output.txt should have this content:

{"val":"A","secret":1}
{"val":"B","secret":2}
{"val":"C","secret":3}
{"val":"D","secret":4}
{"val":"E","secret":5}

*/

const fs = require('fs');
const stream = require('stream');
const highland = require('highland');
const input = fs.createReadStream('input.txt');
const output = fs.createWriteStream('output.txt');

function readStreamThatCreatesData() {
  return highland(input).split().map(JSON.parse);
}

class TransformerStream extends stream.Transform {
  constructor(options) {
    if (!options) {
      options = {};
    }
    options.objectMode = true;
    super(options);
  }
  _transform(item, enc, cb) {
    if (item.secret) {
      item.secret = 'removed';
    }
    item.val = item.val.toUpperCase();
    this.push(item);
    cb();
  }
};

function removeSecret(item) {
  delete item.secret;
  return item;
}

function extractSecret(item) {
  return item.secret;
}

const inputStream = readStreamThatCreatesData();
const secretStream = inputStream.fork().map(extractSecret);
const mainStream = inputStream.fork().map(removeSecret);

secretStream.zip(highland(mainStream.pipe(new TransformerStream())))
  .map((combined) => {
    const secret = combined[0];
    const item = combined[1];
    item.secret = secret;
    return JSON.stringify(item) + '\n';
  })
  .pipe(output);