RxJS 5,将一个observable转换为一个BehaviorSubject(?)

时间:2017-09-13 22:14:20

标签: rxjs rxjs5

我有一个父观察,一旦它有订阅者,将进行查找并发出一个值,然后完成。

我想将其转换为执行以下操作的可观察(或行为主题或其他任何工作):一旦它至少有一个订阅者,它就会从父observable(一次)获得结果。然后它向所有订阅者发出该值,并在订阅时向所有未来订阅者发出该值。即使其订户数量降至零,它仍应继续此行为。

看起来这应该很容易。这是不起作用的:

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

其他不起作用的事情:publishReplay()publish()。更好的东西:

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

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

此方法存在问题:在parent$获得第一个订阅者之前订阅了theValue$

有没有更好的方法来解决这个问题?

3 个答案:

答案 0 :(得分:14)

shareReplay应该做你想做的事:

import 'rxjs/add/operator/shareReplay';
...
theValue$: Observable<boolean> = parent$.shareReplay(1);
在RxJS版本5.4.0中添加了

shareReplay。它返回一个引用计数的observable,它将订阅源 - parent$ - 在第一次订阅时。在源完成后进行的订阅将收到重播通知。

shareReplay - 和refCount一般 - 在我最近写的一篇文章中有更详细的解释:RxJS: How to Use refCount

答案 1 :(得分:4)

我实现了一种将Observables转换为BehaviorSubjects的方法,因为我认为shareReplay方法不太可读,以备将来参考。

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

答案 2 :(得分:0)

这是the tmuechsch's answer的增强版本。

import { Observable, BehaviorSubject } from 'rxjs';

export function convertObservableToBehaviorSubject<T>(observable: Observable<T>, initValue: T): BehaviorSubject<T> {
  const subject = new BehaviorSubject(initValue);
  const subscription = observable.subscribe(subject);
  return {
    subject,
    stopWatching: () => subscription.unsubscribe()
  };
}

请小心,因为返回的主题永远不会从可观察的来源退订。当您知道不再有对stopWatching的引用时(例如,当视图组件被破坏/卸载时),您需要手动调用subject。否则会导致内存泄漏。

为给定的问题提供绝对安全的解决方案是不可能。原因是行为主体具有value属性,即使该主体尚未订阅,也必须始终对其进行更新,因此,当每个人都从{{1}退订时,您不能自动退订observable }}。

cartant's解决方案也不完美,因为结果不是subject,并且instanceof BehaviorSubject仅在订阅时记录值。