I need something like an Observable that calls a webservice exactly once, and return its result to all subscribers. Subscriptions may happen before or after the call. How can I do that?
A Subject
will give an answer to all clients that subscribed before, not after.
const s: Subject<number> = new Subject();
s.next(1);
s.subscribe(x => {console.log(x)}); // will not print anything
A BehaviourSubject
requires a dummy initial value, and clients that subscribed before the call will get the dummy value instead of the right one.
const s: BehaviorSubject<number> = new BehaviorSubject(123);
s.subscribe(x => {console.log(x)}); // will print dummy value 123, then 1
s.next(1);
I tried creating my own Observable
, however in this case the webservice could be called more than once
let val: number|undefined = undefined;
const s = new Observable((observer) => {
if (val !== undefined) {
observer.next(val);
} else {
doMyHttpCall().subscribe({
response => {
this.val = 1;
observer.next(val);
});
}
});
s.subscribe(x => {console.log(x)});
s.subscribe(x => {console.log(x)}); // two clients may give two calls
What is the correct way to do that?
To share an observable response without making multiple calls to your webservice, you can simply use the shareReplay
operator.
export class WebService {
data$ = this.http.get(ENDPOINT).pipe(
shareReplay(1)
);
constructor(private http: HttpClient) { }
}
The first time a consumer subscribes to data$
, the http.get() call will be made. Any subsequent subscribers will simply receive the replayed response.
Here's a StackBlitz demo