我发现使用异步管道和在模板中手动订阅 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 (使用默认值)每个周期都重新订阅异步管道吗?或者异步管道是否使用某种“重试”逻辑?