angular2可观察扫描一次然后由许多异步订阅

时间:2016-01-07 14:06:19

标签: angular rxjs

我需要在不同的时刻绑定共享的observable两次。第一次评估时,第二个绑定会获得null,直到出现下一个项目。

这里是组件类:

export class App {
  subject = new BehaviorSubject(1);
  scan = this.subject.scan((current, change) => current + change, 0).share();
  other = this.scan.map(item => item);
}

这是模板:

<div>
  <button (click)="clickedScan=true">show scan</button>
  <button (click)="clickedOther=true">show other</button>
  <button (click)="subject.next(1)">next</button>
  <div *ngIf="clickedOther">
    other | async: <b>{{ '' + (other | async) }}</b>
  </div>
  <div *ngIf="clickedScan">
    scan | async: <b>{{ '' + (scan | async) }}</b>
  </div>
</div>

这里是plunker更新:plunker已更新为已接受的答案)

share()是必需的,因为否则会为每个订阅者重复调用scan方法,但是在一段时间后完成的下一个async绑定无法访问最后一个元素。如果不使用share(),所有绑定从一开始就起作用,但每次scan调用都会调用subject.next()两次(在此plunker示例中的单独项目实例上)。我想避免这种重复的scan呼叫有很多原因 - 至少不要为每个用户重复完全相同的工作,结果相同。

我想知道什么是避免多个share(即使用其他Observable方法)调用的正确方法,并且每当新async绑定时仍然提供最后一个元素。

1 个答案:

答案 0 :(得分:4)

是的,您需要一个热的可观察对象,以便您共享一个子服务而不是单独的订阅。您可能对Andre的视频感兴趣:https://egghead.io/lessons/rxjs-demystifying-cold-and-hot-observables-in-rxjs。您可能也对Paul Taylor在Reactive 2015中的演讲感兴趣:https://youtu.be/QhjALubBQPg?t=385

基本上,您可以像这样重写代码:

import {Subject, ReplaySubject} from "rxjs/Rx"; // only really need these two

/* your other code */

export class App {

  // plain old subject for clicks
  // i believe you can get an event stream somewhere?
  // sorry, i don't know angular2
  subject = new Subject();

  // replays the last event for observers on subscription
  main = new ReplaySubject(1);

  // you could apply transforms here if you want
  scan = this.main
  other = this.main

  constructor() {
    // take the events that come in
    this.subject

      // start our observable with an initial event
      .startWith(0)

      // when subject emits, this will run and update
      .scan((current, change) => current + change)

      // now we can subscribe our replay subject
      .subscribe(this.main);
  }
}

希望这有帮助。