使用switchMap进行Angular 4 RxJS轮询

时间:2017-09-13 11:01:55

标签: javascript angular rxjs observable

我最近问了一个与订阅丢失有关的问题,如果switchMap遇到错误:

Angular 4 losing subscription with router paramMap using switchMap

解决方案是返回一个空的Observable,因为一次Observable遇到错误,订阅将被销毁。

我现在需要弄清楚如何使用相同的代码进行轮询,但是一旦API返回数据就停止轮询 - 我相信返回这个空的Observable会导致我的轮询代码无法按预期工作。

当前代码没有投票:

ngOnInit() {
  this.subscription = this.route.paramMap
    .switchMap( (params) => {
      this.setChartDefaults();
        return this.getForecastData(params.get('id'))
    .do(null, (err) => {
      this.errorText = err.statusText
      this.loading = false;
    })
    .catch( () => { return Observable.empty() });
  })
}

ngAfterViewInit() {
  this.subscription.subscribe( (data) => {
    // business logic
  }
}

建议代码 WITH POLLING:

ngOnInit() {
  this.subscription = this.route.paramMap
    .switchMap( (params) => {
      return Observable
      .interval(10000)
      .startWith(0)
      .flatMap( () => {
        return this.getForecastData(params.get('id'))
      })
      .filter( (val) => {
        return val.Interval != null
      })
      .take(1)
      .map((forecast) => forecast)
      .do(null, (err) => {
        this.errorText = err.statusText
        this.loading = false;
      })
      .catch( () => { return Observable.empty() });
  })
}

ngAfterViewInit() {
  this.subscription.subscribe( (data) => {
    // business logic
  }
}
  1. route.paramMap上的switchMap,表示任何以前的Observable都被取消
  2. 返回间隔为10秒并立即启动的新Observable
  3. flatMap HTTP请求和轮询Observables
  4. 过滤传入的数据,如果它具有Interval属性,则接受它并停止轮询
  5. map返回订阅
  6. 所需的新observable
  7. catch是返回一个空的observable来处理原始问题
  8. 这段代码总是取第一个结果(使用take(1))然而我的理解是,如果你先过滤,你可以实际上只取第一个有效的结果(在我的情况下有一个有效的响应) )。

    这是我当前的,有限的理解,并且相信我的知识中存在明显的差距,所以我试图更多地了解这些运算符和Observables的链接是如何工作的。

1 个答案:

答案 0 :(得分:2)

因此,在对RxJS Observables如何运作进行更多研究之后,我发现我不应该让错误“传播”到链中并有效地取消我的订阅。我还简化了我的代码:

public getForecastData(forecastId) : Observable<any> {
  return this.http
    .get<any>('/api/forecasts/' + forecastId)
    .map( res => res)
    .catch( () => Observable.empty());
}

ngOnInit() {
  let $pollObservable = Observable
    .interval(8000)
    .startWith(0);

    this.subscription = this.route.paramMap
      .switchMap( (params) =>
        $pollObservable
        .switchMap( () => {
          this.setChartDefaults();
          return this.getForecastData(params.get('id'))
        })
      .filter( (val) => {
        return val.Interval != null
      })
      .take(1)
      .map( forecast => forecast)
      )
}

ngAfterViewInit() {
  this.subscription.subscribe( (data) => {
    // business logic
  });
}

我想我可以用flatMap换掉第二个switchMap运算符,但我想确保取消之前的(外部)Observable。