如何使用highland.js分叉流?

时间:2017-02-06 17:38:34

标签: javascript typescript stream highland.js

我有一个由sourceStream个对象组成的BaseData

我想将此流转换为n - 大量不同的流,然后根据自己的喜好过滤和转换每个BaseData对象。

最后,我想让n个流只包含特定类型,并且分叉流的长度可能不同,因为将来可能会丢弃或添加数据。

我以为我可以通过fork

来设置它
import * as _ from 'highland';

interface BaseData {
    id: string;
    data: string;
}

const sourceStream = _([
    {id: 'foo', data: 'poit'},
    {id: 'foo', data: 'fnord'},
    {id: 'bar', data: 'narf'}]);

const partners = [
    'foo',
    'bar',
];

partners.forEach((partner: string) => {
    const partnerStream = sourceStream.fork();

    partnerStream.filter((baseData: BaseData) => {
        return baseData.id === partner;
    });

    partnerStream.each(console.log);
});

我预计现在有两个流,而foo - 流包含两个元素:

{ id: 'foo', data: 'poit' }
{ id: 'foo', data: 'fnord' }

bar - 流包含一个元素:

{ id: 'bar', data: 'narf' }

然而我得到了一个错误:

/usr/src/marketing-tasks/node_modules/highland/lib/index.js:1338
        throw new Error(
        ^

Error: Stream already being consumed, you must either fork() or observe()
    at Stream._addConsumer (/usr/src/marketing-tasks/node_modules/highland/lib/index.js:1338:15)
    at Stream.consume (/usr/src/marketing-tasks/node_modules/highland/lib/index.js:1500:10)
    at Stream.each (/usr/src/marketing-tasks/node_modules/highland/lib/index.js:1774:18)
    at partners.forEach (/usr/src/marketing-tasks/dist/bin/example.js:17:19)
    at Array.forEach (native)
    at Object.<anonymous> (/usr/src/marketing-tasks/dist/bin/example.js:12:10)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)

如何将流分成多个流?

我也尝试过将这些电话联系起来,然后我才回复了一个流的结果:

partners.forEach((partner: string) => {
    console.log(partner);
    const partnerStream = sourceStream
        .fork()
        .filter((item: BaseData) => {
            return item.id === partner;
        });

    partnerStream.each((item: BaseData) => {
        console.log(item);
    });
});

仅打印:

foo
{ id: 'foo', data: 'poit' }
{ id: 'foo', data: 'fnord' }
bar

而不是预期的:

foo
{ id: 'foo', data: 'poit' }
{ id: 'foo', data: 'fnord' }
bar
{id: 'bar', data: 'narf'}

也许我误解的是fork就是这样的。根据{{​​3}}:

  

Stream.fork()分叉流,允许您添加其他使用者   共同的背压。分叉到多个消费者的流将   只能从最慢的消费者那里快速地从其来源拉取值   处理它们。

     

注意:不要依赖于分叉之间的一致执行顺序。   此转换仅保证所有forks都将处理值foo   在任何人将处理第二个值栏之前。它不保证   叉子处理foo的顺序。

     

提示:小心修改分支中的流值(或   使用这样做的库)。 由于将传递相同的值   每个fork,在一个fork中进行的更改将在任何fork中可见   在它之后执行。添加不一致的执行顺序,和   你最终可能会遇到细微的数据损坏错误。如果你需要修改   任何值,你应该复制并修改副本。

     

弃用警告:目前可以在之后分叉流   消费它(例如,通过变换)。这将不再可能   在下一个主要版本中。如果你要分叉流,总是   对它进行调用。

所以不是&#34;如何分叉流?&#34;我的实际问题可能是:如何将高地流动态复制到不同的流中?

2 个答案:

答案 0 :(得分:1)

partnerStream.filter()会返回流。然后,您使用partnerStream再次使用partnerStream.each(),而不是调用fork()observe()。因此,要么将partnerStream.filter().each()调用链接起来,要么将partnerStream.filter()的返回值分配给变量,并在其上调用.each()

答案 1 :(得分:0)

必须记住,在创建所有分支之前不要使用分叉流。好像一个人消费分叉流,它和它的父母&#34;将被消耗,使任何后续fork从空流中分叉。

const partnerStreams: Array<Stream<BaseData>> = [];

partners.forEach((partner: string) => {
    const partnerStream = sourceStream
        .fork()
        .filter((item: BaseData) => {
            return item.id === partner;
         }
    );

    partnerStreams.push(partnerStream);
});

partnerStreams.forEach((stream, index) => {
    console.log(index, stream);
    stream.toArray((foo) => {
        console.log(index, foo);
    });
});

打印:

0 [ { id: 'foo', data: 'poit' }, { id: 'foo', data: 'fnord' } ]
1 [ { id: 'bar', data: 'narf' } ]