RxJS:用于识别组合流中的流源的正确模式?

时间:2016-03-21 22:30:30

标签: javascript stream rxjs rxjs5 frp

我正在寻找一些关于如何识别哪个流进入mergecombineLatest功能的最佳实践建议,以便只对新流进行操作。

在TODO应用程序的上下文中,我有传入的添加和删除流,我想将它们组合在一起,以便我的列表编辑可以在无状态方式的单个流中进行。输出是一个集成了add(concat)和remove(filter)事件的列表,否则你似乎最终会得到包含所有add或remove事件的其他流,从而无限增长。

遇到的问题包括:

  • 使用merge并不表示传入了哪个流;
  • 使用combineLatest并不表示哪个流已触发订阅的流,因此您不仅可以执行与该流相关的操作。
  • 使用withLatestFrom会导致新的列表无法更新withLatestFrom输入源,因此除非对此列表感兴趣的下一个流订阅该列表,否则列表将不同步(或者你有一个基于前面的新列表的每一个新列表,这导致不必要的重新步骤通过它之前发生的每个转换......)。

目前发现的方法似乎不太理想包括:

  • Cycle JS TODO应用程序直接将type属性明确地分配给早期流的创建对象以供识别,我认为应该避免使用RxJS方法直接识别流来自何处?
  • http://www.jisaacks.com/manipulating-rxjs-streams/获取建议,并将添加流和删除流的输出拆分为[null, {addItem}][removeItem, {null}],以便在使用merge添加和删除事件时,我仍然可以识别正在更新的传入流,以便我可以在单个流中执行添加和删除(但后来我想添加切换事件等,但这似乎也不正确,因为我是需要创建知道所有其他潜在流的流输出(最后以[null,null,myOutput,null,null等]结束。

非常欢迎任何最佳实践建议。

2 个答案:

答案 0 :(得分:1)

您可以在合并之前操作精确流,以避免不必要的ID处理。通常使用流和函数式编程,尽量避免if-else结构,因为有工具可以帮助你。通常你可以通过查看调用的位置来避免它,并采取更早的行动。

这是一个例子。列表操作只是伪操作,以使最重要的部分可见。

let listSubject: Rx.Subject<Item[]> = new Rx.BehaviourSubject<Item[]>([]);
let addObs: Rx.Observable<Item[]> = initAddObs();
let removeObs: Rx.Observable<Item[]> = initRemoveObs();

Rx.Observable
  .merge([
    addObs.map(items => (list: Item[]) => list.concat(items)),
    removeObs.map(items => (list: Item[]) => list.filter(items))
  ])
  .withLatestFrom(listSubject, (operation, list) => operation(list))
  .subscribe(listSubject)

对于列表,使用了BehaviourSubject,因此无论何时订阅,任何人都可以获得最新情况。 AddObs和removeObs流映射到操作,这些操作具有相同的签名并且可以合并。对当前列表执行操作后,我们必须将结果回收到listSubject。现在您可以订阅listSubject,您将获得从那里发出的最新列表。

答案 1 :(得分:0)

没有Rxjs方法可以识别流的来源。流不带有名称。如果你想要一个,你需要自己动手。因此,如果您不喜欢这两种方式,请找另一种方法为它们命名。如果您的问题是在对象上放置标识符的最佳做法,那么答案就是在该死的对象上放置一个标识符。

我个人赞成的方式是通过一个curried函数:

function label(identifier){return function (x){var obj={};obj[identifier]=x;return obj;};}

我使用如下:

source1.map(label('remove')).merge(source2.map(label('add')))

但实际上,请按照您的意愿行事,在我看来,你这样做是一个相当小的问题。