簡體   English   中英

如何通過重新連接實現 shareReplay?

[英]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 的一點:

shareReplay在返回的 observable 的剩余生命周期中保持相同的底層ReplaySubject實例。

一旦ReplaySubject完成,您就不能ReplaySubject任何值,但它仍會重播。 所以...

  1. 您第一次訂閱 observable 並且超時開始。 這將i0增加到1
  2. 您第二次訂閱了 observable 並且超時已經過去了。
  3. 超時回調觸發並發送onNext(i) ,然后是onCompleted()
  4. onCompleted()信號完成了ReplaySubjectshareReplay ,這意味着從現在開始,共享的 observable 將簡單地重放它所擁有的值(即 1)並完成。

關於共享可觀察的一般情況:

另一個單獨的問題是,由於您共享了 observable,它只會調用一次訂閱者函數。 這意味着i只會增加一次。 因此,即使您沒有onCompleted並殺死您的底層ReplaySubject ,您最終也不會將其增加到2

這不是 RxJS 5

一個快速判斷的方法是onNextnext 您當前在示例中使用的是 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.

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