Rxjs:使用来自另一个observable的数据更新可观察流中的值,返回单个可观察流

时间:2016-06-03 09:05:37

标签: javascript rxjs observable

背景

我正在尝试从Stash Rest Api拉取请求中构造一个可观察的值流。不幸的是,PR的合并冲突是否有合并冲突的信息可以在合并列表的不同端点获得。

打开拉取请求列表可以在http://my.stash.com/rest/api/1.0/projects/myproject/repos/myrepo/pull-requests

中看到

对于每个PR,合并冲突的数据在http://my.stash.com/rest/api/1.0/projects/myproject/repos/myrepo/pull-requests/[PR-ID]/merge

处可见

使用atlas-stash包,我可以创建和订阅一个可观察的拉取请求流(每秒更新):

let pullRequestsObs = Rx.Observable.create(function(o) {
    stash.pullRequests(project, repo)
        .on('error', function(error) {o.onError(error)})
        .on('allPages', function(data) {
            o.onNext(data);
            o.onCompleted();
        });
    });

let pullRequestStream = pullRequestsObs
    .take(1)
    .merge(
        Rx.Observable
            .interval(1000)
            .flatMapLatest(pullRequestsObs)
    );

pullRequestsStream.subscribe(
    (data) => {
        console.log(data)
        // do something with data
    },
    (error) => log.error(error),
    () => log.info('done')
);

这可以按照我的意愿和期望进行。最后,pullRequestsStream是一个可观察的,其值是JSON对象的列表。

我的目标

我希望更新pullRequestsStream值,以便列表中的每个元素都包含来自[PR-ID]/merge api的信息。

我认为可以使用map pullRequestsStream来实现这一点,但我没有成功。

let pullRequestWithMergeStream = pullRequestStream.map(function(prlist) {
    _.map(prlist, function(pr) {
        let mergeObs = Rx.Observable.create(function(o) {
            stash.pullRequestMerge(project, repo, pr['id'])
                .on('error', function(error) {o.onError(error)})
                .on('newPage', function(data) {
                    o.onNext(data);
                    o.onCompleted();
                }).take(1);
        });

        mergeObs.subscribe(
            (data) => {
                pr['merge'] = data;
                return pr; // this definitely isn't right
            },
            (error) => log.error(error),
            () => log.info('done')
        );
    });
});

通过一些日志记录,我可以看到pull-request和merge apis都被正确命中,但是当我订阅pullRequestWithMergeStream时我 得到未定义的值。

return内的subscribe步骤中使用map不起作用(似乎不应该这样)但我无法弄清楚什么样的模式/成语会实现我想要的。

有没有正确的方法呢?我完全走错了轨道吗?

TL;博士

我可以使用来自不同的可观察的信息更新Rxjs.Observable中的值吗?

1 个答案:

答案 0 :(得分:2)

您可以使用flatMapconcatMap让一个任务触发另一个任务。您可以使用forkJoin并行请求合并,并将结果收集到一个位置。它没有经过测试,但它应该是这样的:

pullRequestStream.concatMap(function (prlist){
  var arrayRequestMerge = prlist.map(function(pr){
    return Rx.Observable.create(function(o) {...same as your code});
  });
  return Rx.Observable.forkJoin(arrayRequestMerge)
         .do(function(arrayData){
               prlist.map(function(pr, index){pr['merge']=arrayData[index]
             })})
         .map(function(){return prlist})
})

PS:我认为prlist是一个数组。

<强>更新 在您发表评论之后,这是一个只能在并行运行maxConcurrent次调用的版本。

pullRequestStream.concatMap(function (prlist){
  var arrayRequestMerge = prlist.map(function(pr, index){
    return Rx.Observable.create(function(o) {
        stash.pullRequestMerge(project, repo, pr['id'])
            .on('error', function(error) {o.onError(error)})
            .on('newPage', function(data) {
                o.onNext({data: data, index : index});
                o.onCompleted();
            }).take(1);
    });
  });
  var maxConcurrent = 2;
  Rx.Observable.from(arrayRequestMerge)
    .merge(maxConcurrent)
    .do(function(obj){
               prlist[obj.index]['merge'] = obj.data
             })})
    .map(function(){return prlist})
})