如何在node.js中组合变换流

时间:2014-05-16 14:27:47

标签: node.js stream

我有一个csv解析器实现为一系列转换流:

process.stdin
    .pipe(iconv.decodeStream('win1252'))
    .pipe(csv.parse())
    .pipe(buildObject())
    .pipe(process.stdout);

我想抽象解析器(在自己的模块中)并且能够做到:

process.stdin.
    .pipe(parser)
    .pipe(process.stdout);

其中parser只是以前使用的变换流的组合。

如果我这样做

var parser = iconv.decodeStream('win1252')
    .pipe(csv.parse())
    .pipe(buildObject());

然后将parser设置为buildObject()流,只有此转换流接收数据。

如果我这样做

var parser = iconv.decodeStream('win1252');
parser
    .pipe(csv.parse())
    .pipe(buildObject());

它也不起作用,因为.pipe(process.stdout)将在第一个转换流上调用,另外两个将被绕过。

对流优雅组合的任何建议?

3 个答案:

答案 0 :(得分:12)

不幸的是,没有内置的方法可以做到这一点,但有一个很酷的multipipe包。 使用方式如下:

var multipipe = require('multipipe');

var parser = multipipe(iconv.decodeStream('win1252'), csv.parse(), buildObject());

答案 1 :(得分:4)

我一直在努力解决这个问题(以及其他一些问题!)。我发现highlandjs几乎解决了我所有的问题。在这种情况下,他们的pipeline命令可以解决问题:

var h = require('highland');
var parser = h.pipeline(iconv.decodeStream('win1252'), csv.parse(), buildObject());

答案 2 :(得分:0)

我认为现在可以在本地完成。

const { PassThrough, Transform } = require('stream');

const compose = (...streams) => {
  const first = new PassThrough();
  const last = new PassThrough();
  const result = new Transform();

  [first, ...streams, last].reduce(
    (chain, stream) => (
      stream.on('error', (error) => result.emit('error', error)),
      chain.pipe(stream)
    ),
  );

  result._transform = (chunk, enc, cb) => {
    last.once('data', (chunk) => cb(null, chunk));
    first.push(chunk, enc);
  };

  result._flush = (cb) => {
    last.once('end', () => cb(null));
    first.push(null);
  };

  return result;
};