RxJS: `refCount: false` в ShareReplay в сервисе с ограниченной областью действия: будет ли он завершен и будет ли собран мусор при уничтожении сервиса?

Цель:

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

shareReplay({refCount: false, bufferSize: 1})

Наблюдаемый объект объявляется внутри службы, не предоставляемой root, поэтому он будет уничтожен вместе с его обеспечивающим компонентом.

Вопросы:

  • Что произойдет с наблюдаемым, когда компонент + сервис + все подписчики будут уничтожены?

    • Будет ли он завершен и готов к вывозу мусора?
    • Или refCount: false заставит Observable и, следовательно, окружающий контекст (т. е. сервис) храниться где-то в памяти, что приведет к утечке памяти?
  • Нужно ли мне предоставить какой-нибудь помощник по уничтожению, например takeUntilDestroyed() в этом случае, в конце наблюдаемого канала после ShareReplay?

Мысли:

Насколько я знаю

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

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

В случае с этим ограниченным сервисом я предполагал, что применим случай 2 и внутренняя подписка refCount:false будет уничтожена вместе с окружающим контекстом, но я не уверен.

🤔 А знаете ли вы, что...
Angular Universal позволяет рендерить веб-приложение на сервере для улучшения SEO и производительности.


51
1

Ответ:

Решено

Вам придется использовать takeUntilDestroyed или аналогичный подход в своем сервисе, чтобы убедиться, что все было правильно очищено.

Я создал простое приложение, воспроизводящее ваш вариант использования: https://codesandbox.io/p/devbox/vigilant-babycat-f7kt2p

Если вы откроете DevTools и прокомментируете строки 70-71 в test.service.ts, вы увидите, что ваши подписки не очищаются автоматически, если refCount: false. Это потому, что shareReplay немного сложнее, в конечном итоге у вас будет как минимум две подписки: первая подписка внутри share (вы не можете отписаться от нее вручную), остальные — из вашего кода во внутреннюю shareReplayReplaySubject (️ 🔁 исходный код ).

К вашему сведению, first необходим для имитации HTTP-ответа от внутреннего сервера.