[英]How can I achieve a shareReplay with reconnection?
在下面的代碼中,我創建了一個簡單的 observable,它產生一個值然后完成。 然后我分享那個 observable 重放最后一個項目並訂閱 3 次。 第一次緊隨其后,第二次在產生價值之前,第三次在價值產生並且 observable 完成之后。
let i = 0;
let obs$ = Rx.Observable.create(obs => {
console.log('Creating observable');
i++;
setTimeout(() => {
obs.onNext(i);
obs.onCompleted();
}, 2000);
}).shareReplay(1);
obs$.subscribe(
data => console.log(`s1: data = ${data}`),
() => {},
() => console.log('finish s1')
);
setTimeout( () => {
obs$.subscribe(
data => console.log(`s2: data = ${data}`),
() => {},
() => console.log('finish s2')
);
}, 1000);
setTimeout( () => {
obs$.subscribe(
data => console.log(`s3: data = ${data}`),
() => {},
() => console.log('finish s3')
);
}, 6000);
你可以在jsbin上執行這個
這導致以下大理石圖
Actual
s1: -----1$
s2: \--1$
s3: \1$
但我希望
Expected
s1: -----1$
s2: \--1$
s3: \----2$
我可以理解為什么有人想要第一個行為,但我的推理是,與這個例子不同,我返回一個數字,我可能返回一個易受取消訂閱行為影響的對象,例如數據庫連接。 如果上面的彈珠圖表示一個數據庫連接,在 dispose 方法中我調用了db.close()
,那么在第三個訂閱中我會有一個例外,因為我收到的值是一個已發布的數據庫處理程序。 (因為當第二個訂閱完成時 refCount = 0 並且源被釋放)。
這個例子還有另一個奇怪的事情是,即使它用第一個值解析並在之后完成,它訂閱源兩次(正如你在重復的“Creating observable”中看到的那樣)
我知道這個 github 問題談到了這個,但我缺少的是:
如何實現(在 RxJs4 和 5 中)共享的 observable,如果源 observable 尚未完成,則可以重放最后一項,如果完成(refCount = 0),則重新創建 observable。
在 RxJs5 中,我認為 share 方法解決了我問題的重新連接部分,但不能解決共享部分。
在 RxJs4 我一無所知
如果可能的話,我想使用現有的運算符或主題來解決這個問題。 我的直覺告訴我我必須用這樣的邏輯創建一個不同的主題,但我還沒有完全到位。
shareReplay
在返回的 observable 的剩余生命周期中保持相同的底層ReplaySubject
實例。
一旦ReplaySubject
完成,您就不能ReplaySubject
任何值,但它仍會重播。 所以...
i
從0
增加到1
。onNext(i)
,然后是onCompleted()
。onCompleted()
信號完成了ReplaySubject
的shareReplay
,這意味着從現在開始,共享的 observable 將簡單地重放它所擁有的值(即 1)並完成。 另一個單獨的問題是,由於您共享了 observable,它只會調用一次訂閱者函數。 這意味着i
只會增加一次。 因此,即使您沒有onCompleted
並殺死您的底層ReplaySubject
,您最終也不會將其增加到2
。
一個快速判斷的方法是onNext
與next
。 您當前在示例中使用的是 RxJS 4,但是您已經用 RxJS 5 標記了它,並且您在 RxJS 5 中發現了一個問題。RxJS 5 是測試版,是一個完全重寫 RxJS 4 的新版本。 API 更改主要是為了匹配目前處於第 1 階段的es-observable 提案
基本上,您希望在前兩次調用中使用共享版本的 observable,在第三次調用中使用原始 observable。
let i = 0;
let obs$ = Rx.Observable.create(obs => {
console.log('Creating observable');
i++;
setTimeout(() => {
obs.onNext(i);
obs.onCompleted();
}, 2000);
})
let shared$ = obs$.shareReplay(1);
shared$.subscribe(
data => console.log(`s1: data = ${data}`),
() => {},
() => console.log('finish s1')
);
setTimeout( () => {
shared$.subscribe(
data => console.log(`s2: data = ${data}`),
() => {},
() => console.log('finish s2')
);
}, 1000);
setTimeout( () => {
obs$.subscribe(
data => console.log(`s3: data = ${data}`),
() => {},
() => console.log('finish s3')
);
}, 6000);
另外,提示:確保為調用clearTimeout
自定義 observable 返回取消語義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.