Кэширование наблюдаемых объектов вызывает проблемы с картой слияния

#javascript #merge #rxjs #observable #mergemap

Вопрос:

У меня есть метод кэширования в контейнере:

 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$;
}
 

Это прекрасно работает с обычными наблюдаемыми объектами, однако, когда я кэширую нижеприведенное в myContainer2 (например, используя результат кэшированного наблюдаемого для создания другого кэшированного наблюдаемого), например:

 // 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
 

каждый раз, когда второй кэш подписывается на getObs2, вызывается (он ничего не кэширует).
Я подозреваю, что моя реализация get ошибочна, так как я объединяю объект поведения (который излучает в начале), но я не могу придумать никакого другого способа его реализации (чтобы использовать холодные наблюдаемые).
Пожалуйста, обратите внимание, что если я использую обычный наблюдаемый вместо MyContainer.get (), все работает так, как ожидалось.
Вы знаете, в чем заключается проблема?

Комментарии:

1. Похоже, вы пытаетесь рассматривать наблюдаемое свойство как императивное свойство. На самом деле они не предназначены для такого использования. Можете ли вы подробнее рассказать о том, чего вы пытаетесь достичь с помощью этого кода?

2. Я пытаюсь создать контейнер кэширования, который может кэшировать наблюдаемое, но также хранит данные в объекте поведения, чтобы их можно было изменять в течение всего срока службы приложения.

3. Не могли бы вы, пожалуйста, создать простой stackbiltz для имитации того, чего вы пытаетесь достичь?

Ответ №1:

Используя декларативный подход, вы можете обрабатывать кэширование следующим образом:

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

При подписке на config$ приведенный выше код автоматически получит конфигурацию, если она еще не была получена, или вернет полученную конфигурацию.

Я не совсем понимаю, для чего предназначен код BehaviorSubject в вашем примере. Если это должно было содержать исходящие данные конфигурации, в этом нет необходимости, так как config$ они будут предоставлены.

Комментарии:

1. Это будет работать, однако я не смогу обновить полученное наблюдаемое через объект для других операций. например, у меня есть функция обновления контейнера — она выполнит обновление элемента, а затем вызовет subject.next (). Вот почему я объединяю эти два понятия. Однако я не могу понять, почему при выполнении подписки на container2 внутренняя наблюдаемая информация не будет кэшироваться.