web-dev-qa-db-ja.com

RxJs:オブザーバブルの状態に基づいてループする方法は?

RxJに、ストリーム内のObservableを特定の状態になるまでループさせてから、ストリームを続行させようとしています。具体的には、同期do/whileループをRxJに変換していますが、forループまたはwhileループにも同じ答えを使用できると思います。

これにはdoWhile()を使用できると思いましたが、条件関数がストリーム内のアイテムにアクセスできないようで、目的が果たせないようです。

私が望むものに対して正しい反応性の用語が何であるかは完全にはわかりませんが、これが私が目指しているものの例です:

var source = new Rx.Observable.of({val: 0, counter: 3});

source.map(o => {
  o.counter--;
  console.log('Counter: ' + o.counter);

  if (!o.counter) {
    o.val = "YESS!";
  }
  return o;
})
.doWhile(o => { 
  return o.counter > 0; 
})
.subscribe(
    function (x) {
        console.log('Next: ' + x.val);
    },
    function (err) {
        console.log('Error: ' + err);   
    },
    function () {
        console.log('Completed');   
    });

期待される出力は次のとおりです。

Counter: 3
Counter: 2
Counter: 1
Counter: 0
Next: YESS!
Completed

これが解決可能な問題であると仮定すると、ループしたときに戻りたい場所の「開始」をどのようにマークするかがわかりません。

9
JBCP

expand 演算子があり、セレクター関数を再帰的に呼び出すことができます。その場合、空のオブザーバブルを返すことが休憩になります。 jsbin を参照してください:

var source = Rx.Observable.return({val: 0, counter: 3})
    .expand(value =>  { 
      if(!value.counter) return Rx.Observable.empty();
      value.counter -= 1;
      if(!value.counter) value.val = 'YESS';
      return Rx.Observable.return(value)
    })
    .subscribe(value => console.log(value.counter ? 
                                    'Counter: ' + value.counter : 
                                    'Next: ' + value.val));
10
Niklas Fasching

正確には必要なものではありませんが、expand演算子を使用して閉じ、Rx.Observable.emptyで再帰の終了を通知します( http://jsfiddle.net/naaycu71/3/ ):

var source = new Rx.Observable.of({val: 0, counter: 3});

source.expand(function(o) {
  console.log('Counter: ' + o.counter);
  o.counter--;

return (o.counter >= 0) ? Rx.Observable.just(o) : Rx.Observable.empty()
})
.subscribe(
    function (x) {
        console.log('Next: ' , x);
    },
    function (err) {
        console.log('Error: ' + err);   
    },
    function () {
        console.log('Completed');   
    });

出力:

Next:  Object {val: 0, counter: 3}
Counter: 3
Next:  Object {val: 0, counter: 2}
Counter: 2
Next:  Object {val: 0, counter: 1}
Counter: 1
Next:  Object {val: 0, counter: 0}
Counter: 0
Completed
5
user3743222