javascript RxJS:连接三个promise,区分结果
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34055280/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
RxJS: concat three promises, distinguish results
提问by PhiLho
I have three promises, Rest requests returning lists of data.
The third one has references (ids) to the first two lists, so I want to map these ids to corresponding names when I have all the data.
The mapping isn't an issue, I just use Lodash for that.
But the issue is to wait for the three promises to resolve before starting to computing this mapping.
我有三个承诺,Rest 请求返回数据列表。
第三个有对前两个列表的引用(id),所以当我拥有所有数据时,我想将这些 id 映射到相应的名称。
映射不是问题,我只是使用 Lodash。
但问题是在开始计算这个映射之前等待三个承诺解决。
I figured out to use concat()
:
我想出使用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
}
);
My problem is that onNext()
will be called in random order. Ie. I don't know which list I receive at some point, and it is hard to tell from the data it contains.
我的问题是onNext()
将按随机顺序调用。IE。我不知道我在某个时候收到了哪个列表,并且很难从它包含的数据中分辨出来。
Is there a way to track which promises produced which list? A kind of zip? concatMap? concatMapObserver? I admit I haven't fully understood the usage of the last two...
有没有办法跟踪哪些承诺产生了哪些列表?一种拉链?连接映射?concatMapObserver?我承认我还没有完全理解最后两个的用法......
回答by user3743222
If these are promises we are talking about, I think you can have a look at the forkJoin
operator. Cf. 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
如果这些是我们正在谈论的承诺,我想你可以看看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/叉连接.html
You could then have something like :
然后你可以有类似的东西:
Rx.Observable.forkJoin(p1, p2, p3, function(p1,p2,p3){
/* your combining code here */
})
In short, forkJoin
has semantics similar to that of RSVP.all
if you know the promises library RSVP.
简而言之,forkJoin
它的语义类似于RSVP.all
如果您知道 promise 库 RSVP 的语义。
回答by PhiLho
I made some experiments this morning, before going to see if I have an answer... :-)
今天早上我做了一些实验,然后再看看我是否有答案...... :-)
You can see them at http://plnkr.co/edit/3Xczzw
您可以在http://plnkr.co/edit/3Xczzw 上看到它们
I found out that concat of observables will run each observable in turn, in the given order.
我发现 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); }
);
gives
给
{"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
A concat of promises won't deliver anything before the first promise resolves. Then it can deliver (ie. call onNext) the other resolved promises, still in the given order. Then can wait for next promise if any remains, etc.
在第一个承诺解决之前,一系列承诺不会交付任何东西。然后它可以交付(即调用 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); }
);
gives
给
{"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
or
或者
{"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
So, basically, concat respects the order of its arguments, which can be a way to find back which request issued a promise result.
In the case of Ajax requests, better concat the promises than observables, as they will be requested in parallel, not sequentially (unless you need the latter, of course).
因此,基本上, concat 尊重其参数的顺序,这可以作为一种方法来找出哪个请求发出了承诺结果。
在 Ajax 请求的情况下,与 observable 相比,连接 promise 更好,因为它们将被并行请求,而不是顺序请求(当然,除非您需要后者)。
I tried the solution given by @user3743222, and it is a nice one. I prefer forkJoin, as the results are explicitly assigned to parameters, instead of relying on the order.
我尝试了@user3743222 给出的解决方案,这是一个很好的解决方案。我更喜欢 forkJoin,因为结果被明确分配给参数,而不是依赖于顺序。
You have to be aware of differences in error management: I found out that concat will process all promises, until the first error found. While forkJoin will not process anything if one of the promises errors. Which makes sense (we cannot join partial results, in general).
您必须注意错误管理的差异:我发现 concat 将处理所有承诺,直到发现第一个错误。如果其中一个承诺错误,forkJoin 将不会处理任何事情。这是有道理的(通常我们不能加入部分结果)。