我正试图在BaconJs中进行相对复杂的操作。
基本上,我们的想法是继续尝试每个check
,直到您获得“通过”状态或者都失败。问题是“待定”状态有一个Observable列表(由jquery ajax请求构建)将解决检查。出于性能原因,您需要按顺序尝试每个Observable,直到它们全部通过或者一个失败。
这是完整的伪算法:
check
包含id
和status
=失败/通过/待定。如果待处理,则其中包含observables
列表。
这是培根代码。当Observable是Ajax请求时,它不起作用。 基本上,会发生的事情是它跳过挂起的检查....它不会等待ajax调用返回。如果我在filter()之前放置一个log(),它就不会记录挂起的请求:
Bacon.fromArray(checks)
.flatMap(function(check) {
return check.status === 'pass' ? check.id :
check.status === 'fail' ? null :
Bacon.fromArray(check.observables)
.flatMap(function(obs) { return obs; })
.takeWhile(function(obsResult) { return obsResult; })
.last()
.map(function(obsResult) { return obsResult ? check.id : null; });
})
.filter(function(contextId) { return contextId !== null; })
.first();
更新:当检查如下所示时,代码有效:[fail,fail,pending]。但是当检查看起来像这样时它不起作用:[fail,pending,pass]
答案 0 :(得分:3)
我对RxJS比培根更熟悉,但我会说你没有看到所期望的行为是因为flatMap
不等人。
它快速连续传递[fail, pending, pass]
,fail
返回null并被过滤掉。 pending
开始观察,然后接收pass
立即返回check.id
(培根可能不同,但在RxJS中,flatMap不会接受单个值返回)。 check.id会经过filter
并点击first
,此时它就会完成,它只会取消对ajax请求的订阅。
快速修复可能是使用concatMap
而不是flatMap
。
在RxJS中虽然我会重构(免责声明未经测试):
Rx.Observable.fromArray(checks)
//Process each check in order
.concatMap(function(check) {
var sources = {
//If we pass then we are done
'pass' : Rx.Observable.just({id : check.id, done : true}),
//If we fail keep trying
'fail' : Rx.Observable.just({done : false}),
'pending' : Rx.Observable.defer(function(){ return check.observables;})
.concatAll()
.every()
.map(function(x) {
return x ? {done : true, id : check.id} :
{done : false};
})
};
return Rx.Observable.case(function() { return check.status; }, sources);
})
//Take the first value that is done
.first(function(x) { return x.done; })
.pluck('id');
以上是做什么的:
case
运算符进行传播,而不是嵌套的三元组。check.observables
创建一个展平的可观察对象,如果它们都是真的那么我们就完成了,否则继续下一个first
的谓词值来获取已完成的第一个返回值 答案 1 :(得分:2)
我同意@paulpdaniels基于Rx的回答。问题似乎是当使用flatMap
时,Bacon.js不会等到你的第一个“检查流”完成后再启动一个新的。只需将flatMap
替换为flatMapConcat
。
答案 2 :(得分:1)
感谢@raimohanska和@paulpdaniels。答案是使用#flatMapConcat。这将基本上将并行执行的异步调用列表转换为按顺序执行的一系列调用(并注意最后一次"检查"被编程为始终通过以便始终输出内容):
Bacon.fromArray(checks)
.flatMapConcat(function(check) {
var result = check();
switch(result.status) {
case 'pass' :
case 'fail' :
return result;
case 'pending' :
return Bacon.fromArray(result.observables)
.flatMapConcat(function(obs) { return obs; })
.takeWhile(function(obsResult) { return obsResult.result; })
.last()
.map(function (obsResult) { return obsResult ? {id: result.id, status: 'pass'} : {status: 'fail'}; });
}
})
.filter(function(result) { return result.status === 'pass'; })
.first()
.map('.id');