【发布时间】:2020-04-16 14:45:48
【问题描述】:
我有一个医生服务,它有如下 API 调用
patientDetails():Observable<any>
{
return http.get("/home/patient-details")
}
上述服务我订阅了不同的模块组件以获取患者详细信息。在这里我在想如何防止在多个组件中重复 API 调用?
是否可以选择只调用一次 API 并在项目之间共享数据
【问题讨论】:
标签: angular
我有一个医生服务,它有如下 API 调用
patientDetails():Observable<any>
{
return http.get("/home/patient-details")
}
上述服务我订阅了不同的模块组件以获取患者详细信息。在这里我在想如何防止在多个组件中重复 API 调用?
是否可以选择只调用一次 API 并在项目之间共享数据
【问题讨论】:
标签: angular
HttpClient 的方法返回 Cold Observable。要实现您想要的功能,您需要 Hot Observable。您可以使用 shareReplay(numberOfEventsToShare) 将 Cold Observable 转换为 Hot Observable(也称为 Warm Observable,因为它会变暖)并将其存储在属性中。要了解为什么需要这个运算符,您需要知道 Observable 是 Hot 或 Cold 的含义。看看这个great article。
但简而言之,对于您的情况:Hot Observable 共享一个生产者,该生产者甚至可以在有人订阅他之前就产生价值。另一方面,Cold Observable 为每个观察者创建生产者(这意味着不同的观察者之间不会共享该状态)。
因此,shareReplay(1) 运算符将通过共享源并为所有观察者重播 1 个事件(也适用于未来的观察者),使 HttpClient 温暖返回的 observable。
我创建了一个StackBlitz demo,你可以看到即使添加了新组件也没有后续的HTTP请求。
【讨论】:
public patientDetails$: Observable<any>;
constructor(...) {
this.patientDetails$ = http.get("/home/patient-details").pipe(shareReplay(1));
}
【讨论】:
我相信Bardr 和that_guy 提供的答案都需要在服务启动时调用API(因为它们是在构造函数中调用的)。
我希望对多个组件进行非重复的 API 调用,但前提是任何组件都需要该调用。所以它不能依赖于构造函数。我决定以下列方式实现它,其中检查支持的 observable 的值,并且只有当支持的 observable 的值为 null 时才会调用 API。或许可以将此模式与上述答案结合起来。
为我服务:
private foobarReference = new BehaviorSubject<FoobarReference>(null);
public foobarReference$ = this.foobarReference.asObservable();
public getFoobarReferences(): Observable<FoobarReference> {
if (this.foobarReference.getValue() == null) {
this.httpClient.get<FoobarReference>('/api/references/foobar/').subscribe(data => this.foobarReference.next(data));
}
return this.foobarReference$;
}
在我的组件中,我像其他任何 observable 一样订阅它(我使用 takewhile,因为 observable 在服务生命周期内不会改变值):
private this.foobarReferences: FoobarReference;
this.foobarService.getFoobarReferences().pipe(takeWhile(x => x == null, true)).subscribe(data => this.foobarReferences = data);
【讨论】: