Reputation: 3192
I a using angular 4 for one of my projects and i am making a http call to get the data. I cache the data when the data is returned from the backend so that for the subsequent requests i dont have to make the rest calls again and again.
getApplication(): Observable<Array<Application>> {
return new Observable<Array<Application>>((observer) => {
if (this.app&& this.app.length > 0) {
observer.next(this.app)
} else {
this._http
.get<Application[]>(this.url)
.map((app) => this.mapToApp(app))
.subscribe((result: Array<Application>) => {
observer.next(result);
}, () => {
observer.next([]);
})
}
})
}
This works perfectly fine. But if two calls go at the same time, i see there are two requests going in the network tab instead of one. So i tried share() to make satisfy 'One observable, multiple subscribers'.
getApplication(): Observable<Array<Application>> {
return new Observable<Array<Application>>((observer) => {
if (this.app&& this.app.length > 0) {
observer.next(this.app)
} else {
this._http
.get<Application[]>(this.url)
.map((app) => this.mapToApp(app))
.subscribe((result: Array<Application>) => {
observer.next(result);
}, () => {
observer.next([]);
})
}
}).share()
}
But this also, i see there are multiple requests going in the network tab instead of one. What has to be done to make only one call and share the result with all the subscribers ? Please help.
Upvotes: 1
Views: 2347
Reputation: 17762
My first suggestion is to consider a bit of simplification in the code along these lines
getApplication(): Observable<Array<Application>> {
if (this.app && this.app.length > 0) {
return Observable.of(this.app);
}
return this._http
.get<Application[]>(this.url)
.map((app) => this.mapToApp(app))
.do((result: Array<Application>) => {
this.app = result;
}
}
With this logic you can cache using any logic you want. You have decided to check if this.app
is not null and if it has some elements. But you could use any other logic, maybe dependent on the input parameters.
A different story is the problem of 2 calls issued at the same time. In this case you probably want both to share
the Observable so that just one subscription is shared and replay
the last result recorded so that you can return a cached value.
One way of doing this could be the following
private cache$: Observable<Array<Application>>;
requestApplication(): Observable<Array<Application>> {
return this._http
.get<Application[]>(this.url)
.map((app) => this.mapToApp(app))
.do((result: Array<Application>) => {
this.app = result;
}
}
getApplication() {
if(!cache$) {
cache$ = this.requestApplication().shareReplay(1);
}
return cache$;
}
The trick here is performed by the shareReplay
operator. The share part of it makes sure that the subscription is shared. The replay part of it, with a buffer size of 1, makes sure that the last result stored is always returned.
Then you may face the problem of clearing the cache once in a while. But here the story gets more complex and I suggest you to look at this very good article https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.html
Upvotes: 3
Reputation: 664
Do you call the getApplication() method twice? If yes, then you create two different observables.
Maybe you should follow publisher/subscriber pattern using subjects instead?
Upvotes: 0