我有一个父观察,一旦它有订阅者,将进行查找并发出一个值,然后完成。
我想将其转换为执行以下操作的可观察(或行为主题或其他任何工作):一旦它至少有一个订阅者,它就会从父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$
。
有没有更好的方法来解决这个问题?
答案 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
仅在订阅时记录值。