我有一个服务" MyHttpService"包括这样的观察:
grabData() {
return this.http.get('myaddress')
.map((res:Response) => {return res.json()})
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
我有2个组件。 OneComponent和TwoComponent都有" MyHttpService"注入依赖于MyHttpService返回的数据。
OneComponent首先加载。单击按钮后,TwoComponent会加载。
在我拥有的每个组件的onNgInit()中:
this.myHttpService.grabData()
.subscribe(
data => {
// do something to the data
});
假设即使我在两个组件中都有这个订阅,这是正确的,也就是说不会有多个HTTP请求被调用,并且调用" grabData()"当TwoComponent加载时,OneComponent已经提取了相同的数据?还是会打个电话?我想避免多个HTTP请求到同一个端点。如果每次调用具有此功能的组件时都会进行多次调用,那么处理此问题的最佳方法是什么,以便每次初始化TwoComponent时都不会多次调用该服务?
答案 0 :(得分:6)
Http
服务返回所谓的 cold observables 。这意味着每个新订阅者都将导致该observable的工作再次完成,在Http
的情况下,将发出网络请求。
幸运的是,RxJS中有一些机制允许您发布(a.k.a多播或多路复用)一个observable,以便多个订阅者不会导致多个请求。
我通常为Http
执行此操作的方式是使用.publishReplay(1).refCount()
运算符对。 .publishReplay(1)
表示后来的订阅者可以立即获得最新的成功值,而无需另外请求。 .refCount()
表示第一个订阅者发出请求,最后一个订阅者取消订阅会清除原始的Http
可观察对象。
版本5.4.0为这两个运算符添加了一个快捷方式,即.shareReplay(1)
。
只需敲击grabData()
服务方法中该行末尾的任一版本,它就应该像您希望的那样工作。
grabData() {
return this.http.get('myaddress')
.map((res:Response) => {return res.json()})
.catch((error:any) =>
Observable.throw(error.json().error || 'Server error'))
.publishReplay(1).refCount(); // or .shareReplay(1)
}
答案 1 :(得分:4)
您可以使用share运算符进行可观察的多播。这在单个组件中也是相关的,因为对同一osbervable的多个异步绑定将导致多个请求。有一个很好的ng-conf演讲here可以解决这个问题。
import 'rxjs/add/operator/share';
grabData() {
return this.http.get('myaddress')
.map((res:Response) => {return res.json()})
.catch((error:any) => Observable.throw(error.json().error || 'Server error'))
.share();
}
答案 2 :(得分:2)
当您在TwoComponent中订阅时,它将导致再次发送http请求。阻止多个http调用的最佳方法是将响应数据存储在服务中,在http调用之前,检查是否已保存数据,如果是,则直接返回数据。