我试图绕过RxJs运算符groupBy
的用例,我担心在某些情况下它可能会导致内存泄漏。
我熟悉传统意义上的groupBy(例如同步列表处理)。我将写出一个groupBy函数来引用:
const groupBy = f => list =>
list.reduce((grouped, item) => {
const category = f(item);
if (!(category in grouped)) {
grouped[category] = [];
}
grouped[category].push(item);
return grouped;
}, {});
const oddsAndEvens = x => x % 2 === 0 ? 'EVEN' : 'ODD';
compose(
console.log,
groupBy(oddsAndEvens)
)([1,2,3,4,5,6,7,8])
// returns: { ODD: [ 1, 3, 5, 7 ], EVEN: [ 2, 4, 6, 8 ] }
请注意,这在更广泛的范围内是无状态的。我假设RxJs做了类似于此的事情,在EVEN和ODD的位置会有返回的可观察量,并且它会在一些行为类似于集合的状态中跟踪状态。如果我错了,请纠正我,重点是我认为RxJ必须维护所有分组的有状态列表。
我的问题是,如果分组值的数量(本例中只是偶数和奇数)不是有限的,会发生什么?例如,一个流,它为您提供唯一标识符,以保持流的生命周期的一致性。如果你按照这个标识符进行分组,那么RxJs的groupBy运营商会继续制作越来越多的群组,即使旧的标识符永远不会再次被重新访问?
答案 0 :(得分:5)
如果您的流是无限的,并且您的密钥选择器可以生成无限组,那么 - 是的,您有内存泄漏。
您可以为每个分组的observable设置持续时间选择器。为每个组创建持续时间选择器,并在组到期时发出信号。
rxjs 5+:groupBy第三个参数。
rxjs 4:改为使用groupedByUntil运算符。
以下是无限流的示例,其中每个分组的Observable在3秒后关闭。
Rx.Observable.interval(200)
.groupBy(
x => Math.floor(x / 10),
x => x,
x$ => Rx.Observable.timer(3000).finally(() => console.log(`closing group ${x$.key}`))
)
.mergeMap(x$ => x$.map(x => `group ${x$.key}: ${x}`))
.subscribe(console.log)

<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.8/Rx.js"></script>
&#13;
答案 1 :(得分:1)
我的问题是,如果分组值的数量(本例中只是偶数和奇数)不是有限的,会发生什么?
这只能在无限流中发生(因为源流上的值不能超过组)。答案很简单:您将继续创建新的可观察量。
每个GroupedObservable
的生命与源完全一样(当源完成时群组完成),如您所见in the docs:
从技术上讲,这里没有内存泄漏,因为你正在积极地观察无限的可观察量。一旦源可观察完成,所有组也将完成:
source$
.takeUntil(stop$)
.groupBy(…)
但是在技术意义上讲:将一个无限的可观察对一个独特的属性进行分组而没有从源中取消订阅将不会使你的内存使用成为一个大忙,没有。
如果您按照此标识符进行分组,RxJs的groupBy运算符会不断创建越来越多的组,即使旧的标识符也永远不会再次重新访问?
这里需要指出的是,rxjs无法做到这一点。它无法知道某个组是否已完成,或者是否会在以后的某个时间点收到另一个值。