RxJS:连接三个承诺,区分结果

RxJS: concat three promises, distinguish results

我有三个承诺,Rest 请求返回数据列表。
第三个有对前两个列表的引用(ids),所以我想在拥有所有数据后将这些id映射到相应的名称。
映射不是问题,我只是为此使用 Lodash。
但问题是在开始计算这个映射之前等待三个承诺解决。

我想到了使用 concat():

Rx.Observable.concat(p1, p2, p3).subscribe(
function onNext(list)
{
  // Assign the list to the corresponding variable in the scope
},
function onError(e)
{
  // Notify of error
},
function onCompleted()
{
  // Do the mapping
}
);

我的问题是 onNext() 将以随机顺序调用。 IE。我不知道我在某个时候收到了哪个列表,而且很难从它包含的数据中分辨出来。

有没有办法跟踪哪些承诺产生了哪些列表?一种拉链?连接映射?连接地图观察者?我承认我还没有完全理解最后两个的用法...

如果这些是我们正在谈论的承诺,我想您可以看看 forkJoin 运算符。比照。 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/forkjoin.md, http://xgrommx.github.io/rx-book/content/observable/observable_methods/forkjoin.html

然后你可以得到类似的东西:

Rx.Observable.forkJoin(p1, p2, p3, function(p1,p2,p3){
/* your combining code here */
})

简而言之,如果您了解 promises 库 RSVP,forkJoin 的语义类似于 RSVP.all

今天早上我做了一些实验,然后才去看看我是否有答案...:-)

您可以在 http://plnkr.co/edit/3Xczzw

看到它们

我发现 concat of observables 将 运行 每个 observable 按给定的顺序轮流。

  var o1 = Rx.Observable.interval(1500).take(1).map(function (i) { return { n: i, id: 'First', ts: Date.now() - reference }});
  var o2 = Rx.Observable.interval(1000).take(2).map(function (i) { return { n: i, id: 'Second', ts: Date.now() - reference }});
  var o3 = Rx.Observable.interval(2000).take(1).map(function (i) { return { n: i, id: 'Third', ts: Date.now() - reference }});
  // Alternative
  var oa = Rx.Observable.timer(1200).map(function (i) { return { n: i, id: 'Alternative', ts: Date.now() - reference }});

  Rx.Observable.concat(o1, o2, o3, oa).subscribe(
      function onNext(v) { v.timestamp = Date.now() - reference; showObject(v); },
      function onError(e) { var ts = Date.now() - reference; showHTML("Error " + JSON.stringify(e) + " at " + ts); },
      function onCompleted() { var ts = Date.now() - reference; showHTML("Completed at " + ts); }
  );

给予

{"n":0,"id":"First","ts":1503,"timestamp":1503}
{"n":0,"id":"Second","ts":2504,"timestamp":2504}
{"n":1,"id":"Second","ts":3505,"timestamp":3505}
{"n":0,"id":"Third","ts":5506,"timestamp":5506}
{"n":0,"id":"Alternative","ts":6708,"timestamp":6708}
Completed at 6708

在第一个承诺解决之前,一系列承诺不会交付任何东西。然后它可以交付(即调用 onNext)其他已解决的承诺,仍然按照给定的顺序。然后可以等待下一个承诺,如果还有的话等等。

  var p1 = promiseInTime(1500, { id: 'First'});
  var p2 = promiseInTime(1000, { id: 'Second' });
  var p3 = promiseInTime(2000, { id: 'Third' });
  var pa = promiseInTime(1200, { id: 'Failed? ' + !!withFailure }, withFailure);

  Rx.Observable.concat(p1, p2, p3, pa).subscribe(
      function onNext(v) { v.timestamp = Date.now() - reference; showObject(v); },
      function onError(e) { var ts = Date.now() - reference; showHTML("Error " + JSON.stringify(e) + " at " + ts); },
      function onCompleted() { var ts = Date.now() - reference; showHTML("Completed at " + ts); }
  );

给予

{"id":"First","promiseTimeout":1500,"timestamp":1501}
{"id":"Second","promiseTimeout":1000,"timestamp":1506}
{"id":"Third","promiseTimeout":2000,"timestamp":2001}
Error {"id":"Failed? true","promiseTimeout":1201} at 2004

{"id":"First","promiseTimeout":1500,"timestamp":1501}
{"id":"Second","promiseTimeout":1000,"timestamp":1503}
{"id":"Third","promiseTimeout":2000,"timestamp":2000}
{"id":"Failed? false","promiseTimeout":1201,"timestamp":2004}
Completed at 2004

所以,基本上,concat 尊重其参数的顺序,这可以是一种查找哪个请求发出了 promise 结果的方法。
在 Ajax 请求的情况下,concat promises 比 observables 更好,因为它们将被并行请求,而不是顺序请求(当然,除非你需要后者)。

我试了@user3743222给的方案,很不错。我更喜欢forkJoin,因为结果是明确分配给参数的,而不是依赖顺序。

您必须了解错误管理的差异:我发现 concat 将处理所有承诺,直到找到第一个错误。如果其中一个承诺错误,forkJoin 将不会处理任何内容。这是有道理的(我们不能加入部分结果,一般来说)。