我需要对RxJS groupBy运算符执行某些操作,并尝试了解它是如何工作的。
从文档示例中:
const people = [{name: 'Sue', age:25},
{name: 'Joe', age: 30},
{name: 'Frank', age: 25},
{name: 'Sarah', age: 35}];
//Generate source from an array
const source = Rx.Observable.from(people);
//group by age
const example = source
.groupBy(person => person.age)
//accumulates
.mergeMap(group => group.reduce((acc, curr) => [...acc, ...curr], []))
.subscribe(console.log);
输出是:
[{name: "Sue", age: 25}, {name: "Frank", age: 25}]
[{name: "Joe", age: 30}]
[{name: "Sarah", age: 35}]
我需要一些更“反应”的东西,我的意思是,我得到一个无限的流发射值,我需要按时间缓冲,然后对结果进行分组。我的代码与前一代码相似,但不起作用
const subject = new Rx.Subject();
setInterval(() => {
const rnd = Math.random();
const person = rnd < 0.25 ? {name: 'Sue', age: 25} : (rnd > 0.25 && rnd < 0.50) ? {name: 'Joe', age: 30} : 'Sarah', age: 35};
//emits the generated value
subject.next(person);
}, 500);
subject.bufferTime(2000)
.mergeMap(x => Rx.Observable.from(x))
.groupBy(person => person.age)
.mergeMap(group => group.reduce((acc, curr) => [...acc, ...curr], []))
.subscribe(console.log);
正如您所看到的,只是生成代码不同,但我的订阅中没有任何内容。
这是jsbin链接:jsbin example
我做错了什么?
答案 0 :(得分:1)
因为您正在使用mergeMap
将基于时间的缓冲项内联到单个流中,所以流永远不会完成。因此,使用永远不会完成的groupBy
创建组。因此,这些组将永远不会发射到mergeMap,从而将它全部缩减为单个数组。
要完成分组,您可以将.take(XX)
附加到源流,但这不会导致您正在寻找的行为。然后,当原始流同时完成时,所有组都完成。使用RxFiddle.net非常容易找到它:
这种方法的问题是:
为此,您必须对每个缓冲区/窗口值而不是主流进行分组。然后当groupBy完成.reduce()
完成后,您的数组将被发出。
Rx.Observable.interval(500)
.map(i => Math.random())
.map(rnd => rnd < 0.25
? {name: 'Sue', age: 25}
: (rnd > 0.25 && rnd < 0.50)
? {name: 'Joe', age: 30}
: {name: 'Sarah', age: 35}
)
.window(Rx.Observable.interval(2000))
.take(3)
.mergeMap(x => {
return x
.groupBy(person => person.age)
.mergeMap(group => group.reduce((acc, curr) => [...acc, curr], []))
})
.subscribe(val => console.log(val), err => console.log('err: ' + err));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.2.0/Rx.js"></script>
很少有其他注意事项:
Subject
+ setInterval
替换为Rx等效Rx.Observable.interval
+地图window(windowBoundaries)
相当于bufferTime
,但会发出Observable<T>
而不是[]<T>
,因此您可以移除Rx.Observable.from([]<T>)
.reduce((acc, curr) => [...acc, curr], [])
相当于RxJs中可用的.toArray()
函数