簡體   English   中英

rxjs5:延遲取消訂閱共享的observable

[英]rxjs5: Delay unsubscription of a shared observable

我有一個可觀察的創建成本很高,所以我已經shared它。 但是,在某些情況下,所有訂戶都取消訂閱,然后立即(或在短暫延遲之后)訂閱新訂閱者。

實際的可觀察性太復雜了,無法復制,但為了論證:

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

我不想打出創建這個observable所涉及的昂貴代碼。 我想延遲斷開,直到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

如果沒有完全取消訂閱,則不會發出新數據(除非在流的開頭有觸發器,這在您的問題中不明顯)。 - 在您的情況subscription2subscription1subscription2應該收到相同的值。 如果這是設計,那么你可以簡單地不使用refCount()但只是發布然后再做sharedObservable.connect() ,在這種情況下,它總是“熱”。 另一種選擇可能是publishReplay(1)而不是publish()

在任何情況下,你的情況聽起來有點奇怪,並且最有可能通過改變數據流的一般架構來解決 - 但是在不知道真實用例的情況下,很難說rxjs操作是最好的這里。

試圖解決這個問題。 下面的函數包裝提供的ConnectableObservable source並維護訂閱者的refCount。 它在第一個訂閱者訂閱時調用connect() ,然后在最后一個訂閱者取消訂閱調用setTimeout並在delay ms之后unsubscribes source

理想情況下,我寧願修改現有的refCount observable,但我不明白代碼是誠實的。

不確定這是否涵蓋了所有可能的邊緣情況或是否會產生意想不到的副作用。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM