我想从RxJS流中发出所有原始值,然后在完成时发出摘要。
Reduce会停止原始值的发射。扫描会发出每个总数而不是原始值。
这是我的hacky解决方案:
let total = {
total: 0
};
Rx.Observable.range(1, 3)
.do(val => {
total.total += val;
})
.concat(Rx.Observable.of(total))
.subscribe(
value => {
console.log('Next:', value)
}
);
// Next: 1
// Next: 2
// Next: 3
// Next: { total: 6 }
使用纯RxJS流执行此操作的简单方法是什么?
答案 0 :(得分:4)
使用多播
Rx.Observable.range(1, 3)
.multicast(new Rx.Subject(), (shared)=> {
return Rx.Observable.merge(shared, shared.reduce((acc, x)=>acc+x,0))
})
.subscribe(x=>console.log(x))
答案 1 :(得分:2)
作为替代方案,您可以避免使用share()
并制作两个Observable链并只生成一个链:
Observable.range(1, 3)
.concat(Observable.of(null))
.scan((obj, curr) => {
if (curr) {
obj.acc.push(curr);
}
obj.curr = curr;
return obj;
}, { acc: [], curr: 0 })
.map(obj => obj.curr === null
? { total: (obj.acc.reduce((acc, curr) => acc + curr, 0)) } // count total
: obj.curr // just return current item
)
.subscribe(console.log);
这会打印出您期望的结果:
1
2
3
{ total: 6 }
即使使用share()
看起来很简单,也要注意它实际上是两次订阅源Observable。在实践中,根据您将使用的Observable来源,这对您来说不是问题。
试试这个并看到每个数字都打印两次:
let source = Observable.range(1, 3).do(console.log).share();
答案 2 :(得分:1)
怎么样?
let source = Observable.range(1, 3).share();
let totalOb = source
.reduce((total, value) => total + value, 0);
source
.concat(totalOb)
.subscribe( value => console.log(`Next: ${value}`) );
输出:
Next: 1
Next: 2
Next: 3
Next: 6
您可以使用throw
和catch
分隔数据和摘要。
let source = Observable.range(1, 3).share();
let totalOb = source
.reduce((total, value) => total + value, 0)
.mergeMap(total => Observable.throw(total));
source
.concat(totalOb)
.subscribe(
value => console.log(`Next: ${value}`),
value => console.log(`Total: ${value}`)
);
输出:
Next: 1
Next: 2
Next: 3
Total: 6