我有一个服务,它使用 Observable 在其构造函数中加载一些数据。然后在稍后的某个时间可以使用 getter 检索数据。如果数据存在,它应该立即返回数据。或者等待加载完成(如果仍在进行中)。我想出了以下示例(代码在 Typescript 中):
class MyService {
private loadedEvent = new Subject<any>();
private loaded = false;
private data: any;
constructor(
private dataService: DataService
) {
this.dataService.loadData().subscribe(data => {
this.data = data;
this.loaded = true;
this.loadedEvent.next(null);
});
}
public getDataOrWait(): Observable<any> {
if (this.loaded) { // A
return of(this.data);
}
return new Observable((observer: Observer<any>) => {
const subscription = this.loadedEvent.subscribe(() => { // B
observer.next(this.data);
observer.complete();
subscription.unsubscribe();
});
});
}
}
有没有更简单的方法来做到这一点?这一定是一个常见的模式。
另外,我认为如果在执行位于标记 A 和 B 的行之间时加载完成,则存在竞争条件(我不确定这里是否涉及线程 - 然而数据是异步加载的)。
您所要做的就是使用分享重播() https://www.learnrxjs.io/operators/multicasting/sharereplay.html操作员:
class MyService {
public data$: Observable<any>;
public loaded$: Observable<boolean>;
constructor(private dataService: DataService) {
this.data$ = this.dataService.loadData().pipe(
shareReplay(1);
);
this.loaded$ = this.data$.pipe(
mapTo(true),
startWith(false)
);
}
}
The shareReplay
运算符是一个多播运算符,它将向所有订阅者发出相同的先前值。订阅者将等待,直到第一个值可用。
然后你可以使用它data$
创建一个loaded$
可观察到的会发射false
until data$
最后发出一个值,然后它会一直发出true
当值准备好时。
或者,您可以有data$
emit a null
在数据准备好之前,然后是数据。下游有一些逻辑上的好处,允许您在数据准备好或未准备好时创建新的可观察量。
this.data$ = this.dataService.loadData().pipe(
startWith(null),
shareReplay(1);
);
你必须打电话myService.data$.subscribe()
触发流的第一次读取以使数据准备好。您可以在构造函数中执行此操作,但请记住,Angular 在首次使用之前不会创建服务。如果您希望立即加载数据,请在路由中使用解析器或将服务注入到NgModule
构造函数并在那里订阅。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)