RxJS 5, преобразование наблюдаемого в BehaviorSubject (?)

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

Я хотел бы преобразовать это в наблюдаемый (или объект поведения или что-то другое), который делает следующее: после того, как он имеет хотя бы одного абонента, он получает результат от наблюдаемого родителя (один раз). Затем он выдает это значение всем своим подписчикам, а также передает это единственное значение всем будущим подписчикам, когда они подписываются. Он должен продолжать это поведение, даже если его количество подписчиков падает до нуля.

Кажется, это должно быть легко. Вот что не получилось:

theValue$: Observable<boolean> = parent$
.take(1)
.share()

Другие вещи, которые не работали: publishReplay(), publish(). Что-то, что сработало лучше:

theValue$ = new BehaviorSubject<boolean>(false);

parent$
.take(1)
.subscribe( value => theValue$.next(value));

Существует проблема с этим подходом, хотя: parent$ подписан до того, как theValue$ получит своего первого абонента.

Есть ли лучший способ справиться с этим?

Ответ 1

shareReplay должен делать то, что вы хотите:

import 'rxjs/add/operator/shareReplay';
...
theValue$: Observable<boolean> = parent$.shareReplay(1);

shareReplay был добавлен в RxJS версии 5.4.0. Он возвращает ссылочный счетный наблюдаемый, который будет подписываться на источник - parent$ - при первой подписке. И подписки, которые создаются после завершения исходного кода, получат повторные уведомления.

shareReplay - и refCount в целом - объясняется более подробно в статье, которую я написал недавно: RxJS: Как использовать refCount.

Ответ 2

Я реализовал метод для преобразования Observables в BehaviorSubjects, так как я думаю, что метод shareReplay method не очень читабелен для дальнейшего использования.

import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

export function convertObservableToBehaviorSubject<T>(observable: Observable<T>, initValue: T): BehaviorSubject<T> {
    const subject = new BehaviorSubject(initValue);

    observable.subscribe(
        (x: T) => {
            subject.next(x);
        },
        (err: any) => {
            subject.error(err);
        },
        () => {
            subject.complete();
        },
    );

    return subject;
}