RxJS:在组合流中识别流源的正确模式?
RxJS: correct patterns for identifying stream source in combined stream?
我正在寻找一些最佳实践建议,以了解如何以仅对新流进行操作的方式识别哪个流正在进入 merge
或 combineLatest
函数。
在 TODO 应用程序的上下文中,我有传入的添加和删除流,我想将它们组合起来,以便我的列表编辑可以在单个流中以无状态方式进行。输出是一个集成了 add(concat) 和 remove(filter) 事件的列表,否则你似乎会得到包含所有添加或删除事件的其他流,从而无限增长。
遇到的问题包括:
- 使用
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 etc] 结束)。
非常欢迎任何最佳实践建议。
没有 Rxjs 方法可以识别流的来源。流上没有名称。如果你想要一个,你需要自己放。因此,如果您喜欢这两种方式中的 none,请寻找另一种方式为它们命名。如果您的问题是在对象上放置标识符的最佳做法是什么,那么答案就是在该死的对象上放置标识符。
我个人喜欢的方式是通过柯里化函数:
function label(identifier){return function (x){var obj={};obj[identifier]=x;return obj;};}
我使用如下:
source1.map(label('remove')).merge(source2.map(label('add')))
但实际上,随心所欲,如何做到这一点在我看来是一个相当小的问题。
您可以在合并之前操作精确的流,以避免不必要的 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,您将获得从那里发出的最新列表。
我正在寻找一些最佳实践建议,以了解如何以仅对新流进行操作的方式识别哪个流正在进入 merge
或 combineLatest
函数。
在 TODO 应用程序的上下文中,我有传入的添加和删除流,我想将它们组合起来,以便我的列表编辑可以在单个流中以无状态方式进行。输出是一个集成了 add(concat) 和 remove(filter) 事件的列表,否则你似乎会得到包含所有添加或删除事件的其他流,从而无限增长。
遇到的问题包括:
- 使用
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 etc] 结束)。
非常欢迎任何最佳实践建议。
没有 Rxjs 方法可以识别流的来源。流上没有名称。如果你想要一个,你需要自己放。因此,如果您喜欢这两种方式中的 none,请寻找另一种方式为它们命名。如果您的问题是在对象上放置标识符的最佳做法是什么,那么答案就是在该死的对象上放置标识符。
我个人喜欢的方式是通过柯里化函数:
function label(identifier){return function (x){var obj={};obj[identifier]=x;return obj;};}
我使用如下:
source1.map(label('remove')).merge(source2.map(label('add')))
但实际上,随心所欲,如何做到这一点在我看来是一个相当小的问题。
您可以在合并之前操作精确的流,以避免不必要的 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,您将获得从那里发出的最新列表。