使用async管道及实时功能场景下如何正确关闭loader加载器
解决方案
核心原因
你当前使用的Firebase valueChanges() 返回的是永不完结的热流,只有订阅被取消(对应async管道绑定的组件销毁时)才会触发finalize操作符,所以无法在首次数据加载完成后关闭loader。
最优实现方案
你只需要在首次拿到返回数据时执行loader关闭逻辑,不影响后续的实时推送更新即可,修改component.ts代码如下:
private getAlerts(loader: HTMLIonLoadingElement): void { // 标记loader是否已关闭,避免重复执行关闭逻辑 let isLoaderDismissed = false; this.alertsChanged$ = this.alertsService.getAlerts().pipe( tap({ next: (res) => { if (!isLoaderDismissed) { this.loadingService.dismissLoader(loader); isLoaderDismissed = true; } }, error: () => { // 接口报错时也关闭loader,避免loading一直展示 if (!isLoaderDismissed) { this.loadingService.dismissLoader(loader); isLoaderDismissed = true; } } }), map((res) => res) ); }
其他可选方案
如果不想额外声明标记变量,也可以单独订阅一次首帧数据用来关loader,需要注意给源流添加多播操作符避免重复请求:service.ts修改:
getAlerts(): Observable<AlertModel[]> { return this.angularFireDatabase .list<AlertModel>(`groups/${this.groupId}/alerts`) .valueChanges() .pipe(shareReplay(1)); // 多播共享结果,避免重复发起数据库请求 }
component.ts修改:
private getAlerts(loader: HTMLIonLoadingElement): void { this.alertsChanged$ = this.alertsService.getAlerts(); // 单独取首帧数据关闭loader,不影响主源流的实时更新 this.alertsChanged$.pipe(take(1)).subscribe({ next: () => this.loadingService.dismissLoader(loader), error: () => this.loadingService.dismissLoader(loader) }) }
以上两种方案都不需要修改模板的async管道逻辑,也不会影响实时数据推送功能。
内容的提问来源于stack exchange,提问作者Sampath
相关产品推荐
相关产品推荐

