我有一个服务呼叫,其响应被缓存在我的Angular服务中,如下所示:
public cacheMyServiceResponse(): Observable<any> {
return this.appConfig.getEndpoint('myService')
.pipe(
switchMap((endpoint: Endpoint) => this.http.get(endpoint.toUrl())),
tap((body: any) => {
if (body) { // this endpoint can also return a 204 (No Content), where body is null
this.cache = body.myData;
}
}),
take(1),
catchError(error => {
this.errorService.trackError(error.status);
return of(true);
})
);
}
因此,我的http.get调用的响应将存储在一个名为“ cache”的全局变量中。
问题是,此调用实际上可能响应得很晚,因此我们希望在页面加载时(初始化时)立即调用此端点。 但是实际的响应,或者我们的呼叫是否结束(成功还是错误),只有在用户单击按钮时才需要此信息。当然,在单击按钮的那一刻,响应可能尚未出现,并且在这种情况下,我要等待。 (因此,我需要的不仅仅是一个简单的布尔标志)
所以我想像这样在ngOnInit中初始化此调用:
ngOnInit() {
this.myService.cacheMyServiceResponse().subscribe();
}
但是在其他地方,我需要知道它是否已经结束通话,而无需两次触发http通话。
onClick() {
this.myService.cacheMyServiceResponse().subscribe(() => {
// call is finished..
});
}
目前,该服务将被调用两次。我该怎么办?
PS:我没有故意进行错误处理,我只需要知道服务调用是否全部完成即可。
答案 0 :(得分:4)
我建议改为使用ReplaySubject()
并订阅ReplaySubject()
onClick,它会等待您的服务在仍可以订阅的同时发出数据,即使该服务未在订阅之前被订阅服务发出的数据,您将不会丢失数据:
yourWaitingData = new ReplaySubject();
subscription;
ngOnInit() {
this.myService.cacheMyServiceResponse().subscribe(res => {
//yourWaitingData only emit when res is return from API call
this.yourWaitingData.next(res)
});
}
然后订阅它:
onClick() {
if(this.subscription){
this.subscription.unsubscribe()
}
this.subscription = this.yourWaitingData.subscribe((x) => {
// subscribed and will wait for data to be emited from service
console.log(x)
});
}
答案 1 :(得分:1)
您可以在此处为场景使用Resolvers
。当您点击路线时,它将调用您的方法。
示例:
@Injectable()
export class ExampleResolver implements Resolve<any> {
constructor(private apiService: APIService) {}
resolve(route: ActivatedRouteSnapshot) {
return this.apiService.getItems(route.params.date);
}
}
您的路线:
{
path: 'routeName',
component: YourComponent,
resolve: { items: ExampleResolver }
}
答案 2 :(得分:0)
使用布尔变量检查实际响应的状态,或者我们的调用是否完成(成功还是错误);然后可以在用户单击按钮时检查此布尔值...以下代码解释我的意思...
callMade:boolean = false;
callFinished:boolean = false;
ngOnInit(){
this.callMade = true;
this.myService.cacheMyServiceResponse().subscribe(
dataa => { /* get and process data */}
,() => { /*this is the finally block */
this.callFinished = true;
}
);
}
someOtherFunction(){
if (this.callMade == true && this.callFinished == false){
/* call the service again */
}
}
答案 3 :(得分:0)
为什么不保存Observable?
public cacheMyServiceResponse(): Observable<any> {
if(this.cache) {
return of(this.cache);
else if(!this.currentCall) {
this.currentCall = this.appConfig.getEndpoint('myService')
.pipe(
switchMap((endpoint: Endpoint) => this.http.get(endpoint.toUrl())),
tap((body: any) => {
if (body) { // this endpoint can also return a 204 (No Content), where body is null
this.cache = body.myData;
}
}),
take(1),
catchError(error => {
this.errorService.trackError(error.status);
return of(true);
})
);
}
return this.currentCall;
}
答案 4 :(得分:0)
使用shareReplay
创建一个简单的缓存,该缓存将触发http请求一次,并将其返回值提供给缓存中的所有后续订阅。
服务
private cache$: Observable<any>;
getData(): Observable<any> {
if (!this.cache$) {
this.cache$ = this.requestData().pipe(shareReplay(1));
}
return this.cache$;
}
private requestData(): Observable<any> {
return this.appConfig.getEndpoint('myService')
.pipe(
switchMap((endpoint: Endpoint) => this.http.get(endpoint.toUrl())),
catchError(error => {
this.errorService.trackError(error.status);
return of(true);
})
);
}
组件
您可以多次订阅this.myService.getData()
,而无需触发多个http呼叫。只有第一个订阅会触发呼叫。
ngOnInit() {
this.myService.getData().subscribe();
}
onClick() {
this.myService.getData().subscribe(data => console.log('data from click'));
}