RxJS减少了ReplaySubject

时间:2016-03-18 02:56:53

标签: javascript rxjs reactivex

我正在使用ReactiveX / RxJS版本。

假设我有一个Rx.ReplaySubject,它每2秒发出一个包含id的对象和一个包含值的数组。我想减少这个值数组并得到它们的总和。

问题是ReplaySubject是一个热的可观察对象并且它永远不会完成,至少我不希望它完成,因为我希望每2秒对该对象的总和值。但是为了使用reduce运算符,应该完成observable。那么,我该怎么办?

E.G没有工作代码:

var subject = new Rx.ReplaySubject();

subject.
  map(x => x.transactions).
  // Reduce never concludes because ReplaySubject instance is not completed
  reduce((v1, v2) => v1+v2, 0).
  subscribe(function (value) {
    console.log(value)
  });

setInterval(injectData, 2000);

function injectData () {
  subject.next({id: Date.now(), transactions: [
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)}
  ]});
}

1 个答案:

答案 0 :(得分:5)

考虑使用Observable.prototype.scan()RxJS documentation

scan()基本上聚合了一个observable并发出每个连续的值,而reduce()只在完成时发出结果。 (参见scanreduce的Rx说明)

使用OP代码的示例(此处为fiddle):

var subject = new Rx.ReplaySubject();

subject
  // note: use "selectMany" to flatten observable of observables
  .selectMany(x => Rx.Observable.fromArray(x.transactions))
  // note: use "scan" to aggregate values
  .scan((agg, val) => agg+val.value, 0)
  .subscribe(function (value) {
    console.log(value)
  });

setInterval(injectData, 2000);

function injectData () {
  subject.onNext({id: Date.now(), transactions: [
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)},
    {value: Math.round(Math.random() * 5000)}
  ]});
}

另一个例子:

由于selectMany(),上面的代码会为每个事务发出聚合。如果你只希望它每2秒钟发出一次,那么这是一个很好的时间来使用reduce()这样的(这里是另一个fiddle):

subject
  // note: use "selectMany" to flatten observable of observables
  // note: using "reduce" inside here so that we only emit the aggregate
  .selectMany(x => 
    Rx.Observable
      .fromArray(x.transactions)
      .reduce((agg, val) => agg + val.value, 0)
  )
  // note: use "scan" to aggregate values
  .scan((agg, val) => agg+val, 0)
  .subscribe(function (value) {
    console.log(value)
  });

附加说明:

Rx科目可以完成;您只需在准备就绪时致电onCompleted()。如果您完成主题,您仍然可以使用reduce()。将此fiddle与上面的{。}进行比较。