2016-12-25 110 views
0

我正在學習angular 2和rxjs。我有3個變量,AB C.Rxjs - 訂閱相互依存的觀察對象

  • B依賴於一個
  • C的值取決於A的值與B

我想設置了觀測這樣的:當A更新時,B和C將自動更新。當B被更新時,C將被自動更新。我嘗試了兩種設置,但不能令人滿意。

  • 第一次設置:B訂閱可觀察的A; C訂閱了可觀察到的B ,其中最高爲 A. A中的變化確實級聯到B然後級聯到C,但A的值不是最新的。
  • 第二設置:B訂閱可觀察的A; ç訂閱combineLatest觀察到A和B.此設置的作品,但我通過B獲得兩個更新爲C,第一,然後從A

我如何設置我的觀測/訂閱這樣的:當A是更新後,C只會用A和B的最新值更新一次?

編輯 - 碼ADDED

var A = new Rx.BehaviorSubject(1); 
 
var A_Observable = A.asObservable(); 
 
var B = new Rx.BehaviorSubject(10); 
 
var B_Observable = B.asObservable(); 
 

 
A_Observable.subscribe(function(A_value) { 
 
    var newB = A_value * 10; 
 
    // console.log("B auto updating to " + newB); 
 
    B.next(newB); 
 
}); 
 

 
// LATEST FROM OBSERVABLE 
 
var latestFromObservable = B_Observable.withLatestFrom(A_Observable); 
 
latestFromObservable.subscribe(function(data) { 
 
    console.log("LATEST FROM : Value for A is " + data[1] + " ; Value for B is " + data[0]); 
 
}); 
 

 
// COMBINE ALL OBSERVABLE 
 
var combineAllObservable = Rx.Observable.combineLatest(A_Observable,B_Observable); 
 
combineAllObservable.subscribe(function(data) { 
 
    console.log("COMBINE LATEST : Value for A is " + data[0] + " ; Value for B is " + data[1]); 
 
}); 
 

 
// UPDATE TO A 
 
setTimeout(function(){ 
 
    console.log("UPDATING A"); 
 
    A.next(2); 
 
},1000); 
 

 
// SATISFACTORY RESULT 
 
setTimeout(function(){ 
 
    console.log("SATISFACTORY RESULT : Value for A is 2 ; Value for B is 20 --- CALLED ONLY ONCE WITH LATEST VALUES"); 
 
},2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>

+0

如果您包含代碼而不是代碼的描述,則您的問題會更清晰。 – cartant

回答

0

因爲默認情況下RxJs同步運行代碼代碼的行爲這種方式。爲withLatestFrom情況下一連串事件:

  1. 你推新A值:A.next(2);
  2. RxjS看到,有的A兩種用法:
    1. B -subscription(至上)
    2. withLatestFrom(來自第二位)
  3. RxJs調用B -subscription
    1. 它推動的B
    2. RxjS新的價值看,有是一個B用法:(!與A舊值)C -subscription
    3. RxJs調用C -subscription
  4. A的新值被拉入withLatestFrom,但是C - 未觸發訂閱(因爲它僅由B更新觸發)

可能的解決方案是增加debounceTime(0)。它會迫使裏面的時候withLatestFrom值已經更新C -subscription異步運行。

欲瞭解更多信息,請訪問RxJs的Scheduler

var A = new Rx.BehaviorSubject(1); 
 
var A_Observable = A.asObservable(); 
 
var B = new Rx.BehaviorSubject(10); 
 
var B_Observable = B.asObservable(); 
 

 
A_Observable.subscribe(function(A_value) { 
 
    var newB = A_value * 10; 
 
    // console.log("B auto updating to " + newB); 
 
    B.next(newB); 
 
}); 
 

 
// LATEST FROM OBSERVABLE 
 
var latestFromObservable = B_Observable.debounceTime(0).withLatestFrom(A_Observable); 
 
latestFromObservable.subscribe(function(data) { 
 
    console.log("LATEST FROM : Value for A is " + data[1] + " ; Value for B is " + data[0]); 
 
}); 
 

 
// COMBINE ALL OBSERVABLE 
 
var combineAllObservable = Rx.Observable.combineLatest(A_Observable,B_Observable).debounceTime(0); 
 
combineAllObservable.subscribe(function(data) { 
 
    console.log("COMBINE LATEST : Value for A is " + data[0] + " ; Value for B is " + data[1]); 
 
}); 
 

 
// UPDATE TO A 
 
setTimeout(function(){ 
 
    console.log("UPDATING A"); 
 
    A.next(2); 
 
},1000); 
 

 
// SATISFACTORY RESULT 
 
setTimeout(function(){ 
 
    console.log("SATISFACTORY RESULT : Value for A is 2 ; Value for B is 20 --- CALLED ONLY ONCE WITH LATEST VALUES"); 
 
},2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>

我想補充兩點:

  1. withLatestFrom的方法是在你的情況比較好,因爲依賴圖看起來像C -> B -> A當A更新B被過更新。如果AB是獨立的,那麼combineLatest將是更好的選擇。
  2. 無需在SubjectB。您可以改寫這樣的代碼(沒有debounceTime!)

var A = new Rx.BehaviorSubject(1); 
 
var A_Observable = A.asObservable(); 
 

 
var B_Observable = A_Observable.map(function(A_value) { 
 
    var newB = A_value * 10; 
 
    // console.log("B auto updating to " + newB); 
 
    return newB; 
 
}); 
 

 
var latestFromObservable = B_Observable.withLatestFrom(A_Observable); 
 
latestFromObservable.subscribe(function(data) { 
 
    console.log("LATEST FROM : Value for A is " + data[1] + " ; Value for B is " + data[0]); 
 
}); 
 

 
// UPDATE TO A 
 
setTimeout(function(){ 
 
    console.log("UPDATING A"); 
 
    A.next(2); 
 
},1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>

+0

感謝您的詳細解釋。您的解決方案適用於我。 – user1618525

0

好了,所以我與您的代碼進行測試。調整以改變一些事情。你可以在這裏看到代碼:https://jsbin.com/zonedirogi/edit?html,js,console,output。主要的變化實際上是從A而不是B,最後從B變成A。然後它按預期工作。

僅供參考,您不需要使用asObservable()將主題轉換爲可觀察。

var a = new Rx.BehaviorSubject(1); 
var b = new Rx.BehaviorSubject(10); 

a.subscribe(x => { 
    b.next(x * 10); 
}); 

a.withLatestFrom(b).subscribe(x => { 
    console.log(x) 
}) 

// UPDATE TO A 
setTimeout(function(){ 
    console.log("UPDATING A"); 
    a.next(2); 
}, 1000); 
+0

我簡化了這個問題。在實際情況下,A和B在不同的類中,我不想將變量作爲主題公開。 – user1618525