等待链式可观察量完成

时间:2017-01-07 10:19:20

标签: javascript node.js rxjs5 angular2-observables

在使用RxJS5实现我想要的东西时遇到一些麻烦 - 我有一个简单的Observables链,以Rx.Observable.interval开头:

const Rx = require('rxjs');

var i = 0;

const obs = Rx.Observable.interval(100)
    .flatMap(function () {
        return Rx.Observable.timer(Math.ceil(500*Math.random()))
            .map(function(val){
                console.log(' => These should all log first => ', val);
                return i++;
            });
    })
    .take(5)
    .merge()  // this doesn't seem to do what I want to do
    .map(function (val) {
        console.log('all done = > ', val);
    });

obs.subscribe();

上面记录了这个:

 => These should all log first =>  0
all done = >  0
 => These should all log first =>  0
all done = >  1
 => These should all log first =>  0
all done = >  2
 => These should all log first =>  0
all done = >  3
 => These should all log first =>  0
all done = >  4

我希望记录下来:

 => These should all log first =>  0
 => These should all log first =>  0
 => These should all log first =>  0
 => These should all log first =>  0
 => These should all log first =>  0

all done = >  [0,1,2,3,4]

很明显,我们并没有等待所有的计时器观察结果完成,因为你会看到"所有完成!"记录了很多次,穿插了"这些应该首先记录"。

如何获得我想要的输出?

通常情况下,我们可以使用zip,但zip的API不适合此用例,因为我们不会在同一个地方同时拥有所有计时器可观察量时间!

如果我的问题不够清楚,这就是我想要做的类比,我们阻止所有回调,直到我们任意完成并收集了所有结果:

const async = require('async');
var i = 0;

async.forever(function(cb){

    process.nextTick(function(){
       console.log('These should all log first');
       const err = i++ === 5;
       cb(err, i);
    });

}, function done(err, results){
    // let's pretend results contains all the i values
    console.log('all done');
});

3 个答案:

答案 0 :(得分:0)

请注意,这基本上会产生我期望看到的日志记录顺序,但我认为这不是正确/最好的方法:

   const {Observable} = require('rxjs');

    const obs = Observable.interval(100)
        .flatMap(function () {
          return Observable.timer(Math.ceil(500*Math.random()))
              .map(function(val){
                  console.log(' => These should all log first => ', val);
              });
        })
        .take(5)
        .takeLast()  // <<<<<<<<<<
        .map(function () {
            console.log('all done');
        })
        .take(1)    // <<<<<<<<<<

   obs.subscribe();

我认为还有更好的方法来实现这一目标。

答案 1 :(得分:0)

@jonsharpe给了我这个答案,基本上有效。问题实际上可以简化为Rx.Observable.interval,我们可以摆脱Rx.Observable.timer映射。这是我们的基本答案:

const Rx = require('rxjs');

const obs = Rx.Observable.interval(100)
    .take(5)
    .map(function(v){
        console.log(v);
        return v;
    })
    .reduce(function (prev, curr) {
        return prev.concat(curr);
    },[])
    .last(function (results) {
        return results;
    })
    .map(function(v){
        console.log(v);
    });


obs.subscribe();

然而,我会非常感兴趣,没有 reduce。

答案 2 :(得分:0)

所以要求是:

  • 让顶级间隔运行N次。
  • 每个间隔应返回Y计时器可观察数组。
  • 接下来应该追踪N次,每次都有Y个可观察数组。

就是这样。这有点天真,但确实有效。

    let timerArrLength = [ 4, 2, 3 ];
    let svc = Rx.Observable.interval(1000)
        .take(timerArrLength.length)
        .map(function ( index ) {
            let arr = [];
            for ( let i = 0; i < timerArrLength [ index ]; i++ ) {
                arr.push ( Rx.Observable.timer ( 1000 ) );
            }
            return arr;
        });


        svc.subscribe(
            function onNext(v){
                console.log('=> v =>',v);
            },
            function onError(e){
                console.error(e);
            },
            function onComplete(){
                console.log('complete');
            }
        );