Home > Enterprise >  return mix of sync and async values from single Observable
return mix of sync and async values from single Observable

Time:05-31

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()
  );
}
  • Related