1

我发现使用异步管道和在模板中手动订阅 observable 之间存在差异,我还没有在任何讨论这些方法之间差异的文章中看到这种差异。

假设我有一个带有 observable 的组件,它侦听重新加载主题@Input() reload = new ReplaySubject<void>(1)(父组件是所有详细组件的列表。

首先,使用 subscribe() 方法,如果 fetch 请求出错,该方法订阅的 observable 也会出错,从而完成并停止发出值。这是意料之中的。如果我将路线更改为不同的细节,重新加载主题会发出,但可观察的组件已完成,因此它不执行任何逻辑:

  @Input() public refresh: Observable<void>;
  private refreshInternal = new ReplaySubject<GridViewParams>(1);
  public refreshInternalObs = this.refreshInternal.asObservable();

  private initializeInternalRefreshListener(): void {
    this.refreshInternalObs
      .pipe(
        switchMap(() => this.httpRequest()),
        takeUntil(this.unsubscriber),
        finalize(() => {
          // fires once after request error
          // observable then completes
          // and no logic ever fires again
        })
      )
      .subscribe(() => {
        // this code is never reached after obervable errors out once
      });
  }

  private initializeExternalRefreshListener(): void {
    this.refresh.pipe(takeUntil(this.unsubscriber)).subscribe(
      () => {
        // fires every time a notification is sent from parent, 
        // even after refreshInterval is completed
        this.refreshInternal.next();
      },
    );
  }

但是,当我改用异步管道方法时,错误后切换路由会获取新值,就好像异步管道在可观察到的错误输出后再次订阅一样。

<!-- gets new data every time even after refreshInternal erroring out -->
<ng-container *ngIf="this.refreshInternalObs | async as data">{{ data | json }}</ng-container>

...

  @Input() public refresh: Observable<void>;
  private refreshInternal = new ReplaySubject<GridViewParams>(1);
  public refreshInternalObs = this.refreshInternal.asObservable();

  private initializeInternalRefreshListener(): void {
    // seems to not get completed after erroring out
    this.refreshInternalObs
      .pipe(
        switchMap(() => this.httpRequest()),
      )
  }

  private initializeExternalRefreshListener(): void {
    this.refresh.pipe(takeUntil(this.unsubscriber)).subscribe(
      () => {
        // fires every time a notification is sent from parent, 
        this.refreshInternal.next();
      },
    );
  }

异步管道是如何做到的?是因为 changeDetection (使用默认值)每个周期都重新订阅异步管道吗?或者异步管道是否使用某种“重试”逻辑?

4

0 回答 0