I have a cache for already fetched objects. My function getListByIds
should return Observable<Model>
. Inside this function I need to check if object exists in cache (check by id) and if not then fetch it from backend. Code using async/await
could be:
public async getListByIds(ids: number[]): Promise<Model> {
return ids.map(id => {
let cached = this.cacheService.get(id); // may return undefined
if (!cached) cached = await this.http.get(baseUrl '/get/' id).toPromise();
return cached;
});
}
I need to convert it to RxJS - to Promise() is deprecated and I want to learn RxJs.
I'd like not to use subscribe()
inside.
CodePudding user response:
The function would look something like this:
import { forkJoin } from "rxjs/observable/forkJoin";
import { of } from "rxjs/observable/of";
public getListByIds(ids: number[]): Observable<Model> {
return forkJoin(ids.map(
(id) => {
let cached = this.cacheService.get(id)
if (!cached) return this.http.get(baseUrl '/get/' id)
return of(cached)
}
)
}
The forkJoin
waits for all mapped Observables to complete.
CodePudding user response:
Here are two different approaches depending on whether you'd like your observable to emit an array of a stream.
// A Stream of Models
public getListByIds(ids: number[]): Observable<Model> {
return from(ids).pipe(
map(id => [id, this.cacheService.get(id)]),
mergeMap(([id, cached]) => !!cached ?
of(cached) :
this.http.get(baseUrl '/get/' id)
)
);
}
// An Array of Models
public getListByIds(ids: number[]): Observable<Model[]> {
return forkJoin(ids
.map(id => [id, this.cacheService.get(id)])
.map(([id, cached]) => !!cached ?
of(cached) :
this.http.get(baseUrl '/get/' id)
)
);
}
For the sake of completeness, you can transform the first into the second with toArray
.
// An Array of Models
public getListByIds(ids: number[]): Observable<Model[]> {
return from(ids).pipe(
map(id => [id, this.cacheService.get(id)]),
mergeMap(([id, cached]) => !!cached ?
of(cached) :
this.http.get(baseUrl '/get/' id)
),
toArray()
);
}