我有一个可观察的创建成本很高,所以我shared
它。但是,在某些情况下,所有订阅者都会取消订阅,然后立即(或在短暂延迟之后)订阅新订阅者。
实际的observable太复杂了,无法复制,但为了论证:
const heavyObservable = Rx.Observable.create((observer) => {
console.log('I am expensive, avoid hitting this code');
return Rx.Observable
.interval(500) // these updates are cheap though!
.subscribe(observer)
.add(() => {
console.log('Cache has been destroyed, will have to be rebuild on next call');
});
});
我不想点击创建此观察所涉及的昂贵代码。我想延迟断开,直到 n ms之后。有没有办法做到这一点?
const sharedObservable = heavyObservable
.publish()
// ideally I'm looking for a way to get refCount to wait for new
// subscribers for n ms before unsubscribing when refcount === 0
.refCount();
// calling subscribe here invokes heavyObservable which can take a bit of time
const subscription1 = sharedObservable.subscribe();
// log: I am expensive, avoid hitting this code
// second call is "free" - the underlying observable is reused
const subscription2 = sharedObservable.subscribe();
subscription1.unsubscribe();
subscription2.unsubscribe();
// calling subscribe again here invokes heavyObservable over again
const subscription3 = sharedObservable.subscribe();
// log: I am expensive, avoid hitting this code
答案 0 :(得分:0)
如果没有完全取消订阅,则不会发出新数据(除非在流的开头有触发器,这在您的问题中不明显)。 - 您的案例中的subscription1
和subscription2
应该会收到相同的值。
如果这是设计的,那么你可以简单地不使用refCount()
,而只是发布然后做sharedObservable.connect()
,在这种情况下,它总是会#34; hot"。
另一个选项可能是publishReplay(1)
而不是publish()
。
在任何情况下,你的情况听起来有点奇怪,并且最有可能通过改变数据流的一般架构来解决 - 但是如果不知道真正的用例,很难说rxjs操作会是什么在这里是最好的。
答案 1 :(得分:0)
试图解决这个问题。下面的函数包装提供的ConnectableObservable source
并维护一个refCount订阅者。当第一个订阅者订阅时,它会调用connect()
,然后当setTimeout
ms之后,最后一个订阅者从unsubscribes
取消订阅调用source
和delay
。
理想情况下,我宁愿修改现有的refCount可观察对象,但我并不理解这些代码是诚实的。
不确定这是否涵盖所有可能的边缘情况或是否会产生意外的副作用。
Plunker:https://jsbin.com/wafahusitu/edit?js,console
function refCountWithUnsubscriptionDelay<T>(source: Rx.ConnectableObservable<T>, delay: number): Rx.Observable<T> {
const refCount = 0;
const sub;
let timeoutRef;
return Rx.Observable.create((observer: Rx.Observer<T>) => {
refCount++;
if (timeoutRef) {
clearTimeout(timeoutRef);
}
console.log('refCount = ' + refCount);
if (!sub) {
// connect on first call
sub = source.connect();
}
return source.subscribe(observer)
.add(function () {
refCount --;
if (refCount <= 0) {
// trigger delayed unsubscription if there are no listeners
timeoutRef = setTimeout(() => {
// don't unsubscribe if new listeners have subscribed
if (refCount <= 0) {
console.log('unsub');
sub.unsubscribe();
sub = undefined;
timeoutRef = undefined;
}
}, delay);
}
});
})
}