RxJs:对第一个和最后一个订阅者采取行动以进行观察

时间:2017-01-13 19:08:36

标签: angular rxjs5

在我的Angular 2.x应用程序中,我有一个订阅服务所公开的observable的组件。目前,可观察数据服务是通过轮询HTTP请求实现的,但这将改为反应式WS实现。我想保留组件中的轮询,所以问题是:一旦我有订阅者,我怎样才能采取行动,比如通过setInterval进行HTTP轮询?而且,如果没有更多订阅者,我该如何采取行动,例如clearInterval

视图是异步更新的:

  <div *ngFor="let headline of headlines$ | async">
    <md-list-item (click)="onSelect(headline)">
      <h4 md-line>{{headline.title}}</h4>
    </md-list-item>
    <md-divider></md-divider>
  </div>

该组件从服务中获取标题:

export class HeadlinesComponent implements OnInit, OnDestroy {
  constructor(
      private _headlineService: HeadlineService,
  ) {
  }

  headlines$: Observable<Headline[]>;

  ngOnInit() {
    this.headlines$ = this._headlineService.headlines$;
  }
}

该服务作为可观察的数据存储实现:

@Injectable()
export class HeadlineService {
  constructor(
    private _http: Http) {
    _init();
  }

  private _headlines$: BehaviorSubject<Headline[]> = 
    new BehaviorSubject<Headline[]>([]);

  get headlines$(): Observable<Headline[]> {
    return this._headlines$.asObservable();
  }

  private _store: {
    headlines: Headline[]
  } = { headlines: [] };

  private _save(headlines: Headline[]) {
    this._store.headlines = headlines;
    this._headlines$.next(Object.assign({}, this._store).headlines);
  }
}

并通过HTTP更新商店:

  private _interval;

  private _init() {
    let self = this;
    this._interval = setInterval(function(){ self._loadHeadlines();}, 5000);
  }

  private _loadHeadlines(): Observable<Headline[]> {
    let self = this;
    let observable: Observable<Headline[]> = this._http
      .get(url, options)
      .map(response => response.json()._embedded.headlines)
      .share();

    observable.subscribe(
      headlines => self._save(headlines)
      );    

    return observable;
  }

实施后,标题服务开始轮询建设而不是延迟直到订户在场。为了使生命周期正确,我可以公开服务的_loadHeadlines功能,并在组件的ngOnInit被触发(并在ngOnDestroy中停止)时开始轮询,但是将服务实现细节暴露给组件(当我转到网络套接字实现时,这些细节会发生变化)我需要准确计算订阅者数量。

那么,有没有一个很好的RxJs-ish方法来解决这个问题?

2 个答案:

答案 0 :(得分:1)

Observables很懒,只在订阅时才开始工作。当您停止收听时,他们将取消订阅并清理。

您正在寻找的是多播行为,在第一次订阅时将refcounting转换为init,并且只有当没有人订阅才能清理时。这是使用.share()运算符完成的。

答案 1 :(得分:0)

我没有在Angular中使用RxJS,但是从你的示例代码中可以看出,你可以.create一个observable来启动轮询间隔并返回清除间隔函数,该函数将在它被调用时被调用。取消订阅。

/*
    Increment value every 1s, emit even numbers.
*/
const evenNumbers = Rx.Observable.create(function(observer) {
    let value = 0;
    const interval = setInterval(() => {
        if(value % 2 === 0){
            observer.next(value);
        }
        value++;
    }, 1000);

    return () => clearInterval(interval);
});
//output: 0...2...4...6...8
const subscribe = evenNumbers.subscribe(val => console.log(val));
//unsubscribe after 10 seconds
setTimeout(() => {
    subscribe.unsubscribe();
}, 10000);

以上示例来自learnrxjs.io

JSBin Example