By using Http, we call a method that does a network call and returns an http observable:
getCustomer() {
return this.http.get('/someUrl').map(res => res.json());
}
If we take this observable and add multiple subscribers to it:
let network$ = getCustomer();
let subscriber1 = network$.subscribe(...);
let subscriber2 = network$.subscribe(...);
What we want to do, is ensure that this does not cause multiple network requests.
This might seem like an unusual scenario, but its actually quite common: for example if the caller subscribes to the observable to display an error message, and passes it to the template using the async pipe, we already have two subscribers.
What is the correct way of doing that in RxJs 5?
Namely, this seems to work fine:
getCustomer() {
return this.http.get('/someUrl').map(res => res.json()).share();
}
But is this the idiomatic way of doing this in RxJs 5, or should we do something else instead?
Note : As per Angular 5 new HttpClient
, the .map(res => res.json())
part in all examples is now useless, as JSON result is now assumed by default.
Per @Cristian suggestion, this is one way that works well for HTTP observables, that only emit once and then they complete:
rxjs 5.4.0 has a new shareReplay method.
The author explicitly says "ideal for handling things like caching AJAX results"
rxjs PR #2443 feat(shareReplay): adds
shareReplay
variant ofpublishReplay
I found a way to store the http get result into sessionStorage and use it for the session, so that it will never call the server again.
I used it to call github API to avoid usage limit.
FYI, sessionStorage limit is 5M(or 4.75M). So, it should not be used like this for large set of data.
------ edit -------------
If you want to have refreshed data with F5, which usesmemory data instead of sessionStorage;
rxjs 5.3.0
I haven't been happy with
.map(myFunction).publishReplay(1).refCount()
With multiple subscribers,
.map()
executesmyFunction
twice in some cases (I expect it to only execute once). One fix seems to bepublishReplay(1).refCount().take(1)
Another thing you can do, is just not use
refCount()
and make the Observable hot right away:This will start the HTTP request regardless of subscribers. I'm not sure if unsubscribing before the HTTP GET finishes will cancel it or not.
It's
.publishReplay(1).refCount();
or.publishLast().refCount();
since Angular Http observables complete after request.This simple class caches the result so you can subscribe to .value many times and makes only 1 request. You can also use .reload() to make new request and publish data.
You can use it like:
and the source:
Have you tried running the code you already have?
Because you are constructing the Observable from the promise resulting from
getJSON()
, the network request is made before anyone subscribes. And the resulting promise is shared by all subscribers.