代码之家  ›  专栏  ›  技术社区  ›  Daniel

rxjs publishReplay:错误时重置

  •  3
  • Daniel  · 技术社区  · 7 年前

    我正在使用publishReplay(1)。refCount()以在Angular5中缓存http请求。这可以很好地工作,除非出现错误。

    我正在接受并报告来自http源的异常,这就是我传递Observable的原因。以下代码中的(未定义)。在这种情况下,它的缓存当然是未定义的,但后续订阅者不应该获得该值,相反,它应该再次请求http资源,就像没有缓存一样。

    我的当前代码:

    result: Observable<any>;
    list() {
    
      if (this.result === undefined) {
        this.result = this.http.get(`https://swapi.co/api/people`)
          .catch(error => {
            console.error("Something really bad happened", error);
            return Observable.of(undefined);
            // in that case, reset publishReplay
          })
          .publishReplay(1)
          .refCount();
      }
    
      return this.result;
    }
    

    我有一个stackblitz(带有shareReplay,但问题相同)来展示这种行为: https://stackblitz.com/edit/angular-s5zuqa . 单击“Load”应该重新请求http源,而不是从catch中提供缓存对象。

    2 回复  |  直到 7 年前
        1
  •  3
  •   Ingo Bürk    7 年前

    如果我理解正确,你是在找这个,对吗?这里有两件重要的事情需要注意:

    1. 我们使用 shareReplay(1) 而不是 publishReplay(1).refCount() .
    2. 这个 catch 已移至 在…的后面 多播运算符。

    您将看到(伪造的)HTTP调用错误在第一次出现时 undefined (因为我们抓住了它)。下一次,我们再次运行该请求,这次得到一个结果(42),该结果将被缓存以用于第三次运行,不会导致另一个请求。

    // Just to keep track of how often we sent the request already
    let counter = 1;
    
    // A fake HTTP request which errors the first time, then succeeds
    const request$ = Rx.Observable.of(null)
      .do(() => console.log('HTTP Request (#' + counter + ')!'))
      .delay(250)
      .switchMap(() => counter++ === 1 
        ? Rx.Observable.throw('Error!')
        : Rx.Observable.of(42)
      );
    
    // =========
    
    const result$ = request$
      .shareReplay(1)
      .catch(() => Rx.Observable.of(undefined))
    ;
    
    Rx.Observable.timer(0, 1000)
      .take(3)
      .do(() => console.log('Subscribing to result$…'))
      .switchMap(() => result$)
      .subscribe(value => console.log('Received value: ', value));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
        2
  •  2
  •   Simon_Weaver    6 年前

    小心使用 shareReplay(1) . 它与退订和参考计数有关。

    正在将新的配置参数添加到 shareReplay() 解决这种情况。

    这里可以更好地解释这个问题:

    https://github.com/ReactiveX/rxjs/issues/3336

    截至今天,新功能即将推出,但尚未发布。

    https://github.com/ReactiveX/rxjs/pull/4059