Rxjs - 订阅相互依赖的可观察量

时间:2016-12-25 02:01:29

标签: angular rxjs reactive-programming rxjs5

我正在学习角度2和rxjs。我有3个变量,A B C。

  • B取决于A
  • 的值
  • C取决于A和B的值

我正在尝试设置observable,以便:当A更新时,B和C将自动更新。更新B时,C将自动更新。我尝试了两种设置,但效果不理想。

  • 首先设置:B订阅可观察的A; C订阅可观察的B withlatestfrom A. A中的变化确实级联到B然后到C,但A的值不是最新的。
  • 第二次设置:B订阅可观察的A; C订阅A和B的 combineLatest 可观察对象。此设置有效,但我得到C的两个更新,首先是B,然后是A../ / li>

如何设置我的observables /订阅,以便在更新A时,C只会使用A和B的最新值更新一次?

编辑 - 添加的代码



<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input />
&#13;
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);
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:0)

代码的行为方式是这样的,因为默认情况下RxJs同步运行代码。 withLatestFrom案件的事件链:

  1. 您推送新的A值:A.next(2);
  2. RxjS发现A有两种用法:
    1. B - 订阅(首先出现)
    2. withLatestFrom(排在第二位)
  3. RxJs调用B - 订阅
    1. 它推动B
    2. 的新价值
    3. RxjS发现使用了BC - 订阅
    4. RxJs调用C - 订阅(旧值为A!)
  4. A中的withLatestFrom的新值被提取但C - 未触发订阅(因为它仅由B更新触发)
  5. 可能的解决方案是添加debounceTime(0)。它将强制C - 订阅在withLatestFrom内的值已更新时异步运行。

    有关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. Subject B无需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);!)
    3. <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script>
      float:left

答案 1 :(得分:0)

好吧,所以我测试了你的代码。调整改变一些事情。您可以在此处查看代码:https://jsbin.com/zonedirogi/edit?html,js,console,output。主要的变化实际上是B而不是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);