有效地创建从可观察集合中过滤特定项目的可观察对象 [英] Efficiently creating observables that filter a specific item from an observable collection

查看:44
本文介绍了有效地创建从可观察集合中过滤特定项目的可观察对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 RxJS 主题,用于发布对集合的更改.每次集合更改时,主题将新内容发布为数组.例如

I have a RxJS subject that publishes changes to a collection. Each time the collection changes, the subject publishes the new contents as an array. E.g.

let collectionSubject = new Rx.BehaviourSubject();

collectionSubject.onNext([{
    id: 1
}]);

我想为客户端代码提供基于按 ID"订阅此集合的功能.例如.当集合更改时,它们仅接收与查询的 id 匹配的项目(如果存在).如果该项目不存在,或刚刚被移除,则它们会收到 undefined.

I want to provide the ability for client code to subscribe to this collection on ‘by id’ basis. E.g. when the collection changes, they receive only the item that matches the queried id, if it is present. If the item isn't present, or has just been removed, they receive undefined.

我可以天真地实现如下:

I could naïvely implement this as follows:

byId(id) {
   return collectionSubject.filter(items => items.find(item => item.id == id));
}

然而,这每次都会创建一个新的 observable,并导致 items 数组的多次重复迭代.我可以使用一个以 id 为键的 Map 来缓存特定 id 的 observables,但这仍然会导致针对不同 id 的 items 数组的多次迭代.

However, this will create a new observable each time, and result in multiple redundant iterations of the items array. I could use a Map, keyed by id, to cache observables for a particularly id, but this would still result in multiple iterations of the items array for different ids.

我能看到的唯一解决方案是编写大量自定义机制来为每个 id 创建、缓存和销毁主题,在集合更改时迭代一次,并将每个项目发布到任何相应的主题.

The only solution I can see is to write a lot of custom machinery to create and cache and destroy subjects for each id, to iterate the collection once when it changes, and publish each item to any corresponding subject.

有没有更简单、更惯用的方法来使用底层的 RxJS 操作符来实现这一点?关键要求是只迭代一次底层集合.

Is there a simpler, more idiomatic way to achieve this using the underlying RxJS operators? The key requirement is to only iterate the underlying collection a single time.

推荐答案

不确定传递的链接是否引导您找到实际解决方案,因此我在此处提供有关可能方法的更多详细信息.这个想法是使用运算符 groupBy,参见.https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/groupby.md , http://reactivex.io/documentation/operators/groupby.html 用于弹珠,如果您喜欢这里的测试规范 https://github.com/ReactiveX/RxJS/blob/master/spec/operators/groupBy-spec.js).

Not sure if the link passed led you to an actual solution, so I give more details here about a possible approach. The idea is to use the operator groupBy, cf. https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/groupby.md , http://reactivex.io/documentation/operators/groupby.html for the marbles and if you fancy here for the tests specs https://github.com/ReactiveX/RxJS/blob/master/spec/operators/groupBy-spec.js).

假设您有一个按 id 划分的观察者地图,称为 observers,您可以尝试类似的方法:

Supposing you have a map of observers by ids, called observers, you could try something along the lines :

collectionSubject = new Rx.Subject();
observers = [0, emits("observer for group 1"), emits("observer for group 2")];

collectionSubject
    .concatMap(function ( arr ) {return arr;})
    .tap(emits("tap"))
    .groupBy(function ( item ) {return item.id;})
    .subscribe(function ( groupObs ) {
                 groupObs.subscribe(function ( item ) {
                   observers[item.id](item);
                 });
               });

collectionSubject.onNext([
  {id : 1, value : "first item / group 1"},
  {id : 1, value : "second item / group 1"},
  {id : 2, value : "first item / group 2"},
  {id : 2, value : "second item / group 2"},
  {id : 1, value : "third item / group 1"},
  {id : 2, value : "third item / group 2"},
]);

测试结果在这里:

"tap emits first item / group 1"
"observer for group 1 emits first item / group 1"
"tap emits second item / group 1"
"observer for group 1 emits second item / group 1"
"tap emits first item / group 2"
"observer for group 2 emits first item / group 2"
"tap emits second item / group 2"
"observer for group 2 emits second item / group 2"
"tap emits third item / group 1"
"observer for group 1 emits third item / group 1"
"tap emits third item / group 2"
"observer for group 2 emits third item / group 2"

jsbin 在这里.https://jsbin.com/qikamamohi/edit?js,console

注意:

  • concatMap 是一种逐项按顺序发出数组内容的技巧
  • the concatMap is a trick to emit the array content item by item and in order

这篇关于有效地创建从可观察集合中过滤特定项目的可观察对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆