1

I have a caching method in a container:

get(): Observable<T[]> {
  if (!this.get$) {
    this.get$ = merge(
      this.behaviorSubject.asObservable(),
      this._config.get().pipe(shareReplay(1), tap(x => this.behaviorSubject.next(x))));
  }

  return this.get$;
}

This works fine with normal observables, however when I cache the bellow in a myContainer2 (e.g using cached observable's result to create another cached observable) method like:

// get is assigned to _config.get in the above function
const myContainer2 = new Container({get: () => myContainer1.get().pipe(mergeMap(res1 => getObs2(res1))});

// please note, the end goal is to resolve the first observable on the first subscription 
// and not when caching it in the above method (using cold observables)
myContainer2.get().subscribe(...) // getObs2 gets called
myContainer2.get().subscribe(...) // getObs2 gets called again
myContainer2.get().subscribe(...) // getObs2 gets called for a third time, and so on

every time when the second cache is subscribed to getObs2 gets called (it caches nothing). I suspect my implementation of get is faulty, since I am merging an behavior subject (which emits at the beginning), but I cant think of any other way to implement it (in order to use cold observables). Please note that if I use normal observable instead of myContainer.get() everything works as expected. Do you know where the problem lies?

  • It looks like you are trying to treat an Observable property like an imperative property. They aren't really meant to be used in that way. Can you elaborate on what you are trying to accomplish with this code? – DeborahK Aug 18 '21 at 21:59
  • I am trying to build a caching container that can caches an observable, but also stores the data in a BehaviorSubject so it can be changed throughout the life of the application. – Aleksandar Angelov Aug 19 '21 at 06:40
  • Could you please create a simple stackbiltz to simulate what you're trying to achieve? – Amer Aug 31 '21 at 17:56

1 Answers1

1

Using a declarative approach, you can handle caching as follows:

// Declare the Observable that retrieves the set of 
// configuration data and shares it.
config$ = this._config.get().pipe(shareReplay(1));

When subscribed to config$, the above code will automatically go get the configuration if it's not already been retrieved or return the retrieved configuration.

I'm not clear on what the BehaviorSubject code is for in your example. If it was to hold the emitted config data, it's not necessary as the config$ will provide it.

DeborahK
  • 57,520
  • 12
  • 104
  • 129
  • This will work, however I would not be able to refresh the retrieved observable via the subject for other operations. e.g I have an update function to the container - it will perform an update of an item and then it will call subject.next(). That is the reason I am merging the two. However, I cant understand why when performing the subscription to container2 the inner observable wont be cached. – Aleksandar Angelov Aug 19 '21 at 07:33