【发布时间】:2017-05-22 01:53:19
【问题描述】:
在使用 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]
很明显,我们并没有等待所有的 timer observables 完成,因为你会看到“all done!”记录了很多次,穿插着“这些都应该先记录”。
我怎样才能得到我正在寻找的输出?
通常情况下,我们可以为此使用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');
});
【问题讨论】:
-
请注意,如果我们用 takeLast() 代替 merge(),我们将在“这些都应该首先记录”之后记录“全部完成”,这是“正确的”,然后是“全部完成”记录了 50 倍!我希望“全部完成”只记录一次 :)
-
take不会对它们进行批处理,它只是在看到足够多时结束流。单个流上的merge根本不做任何事情。看看例如rxmarbles.com/#merge 很好地说明了正在发生的事情。 -
嗯,既然您正在映射元素,您难道不希望“全部完成”记录与元素一样多的次数吗?基于此代码,我实际上希望看到该地图控制台日志触发的次数与您“接受”的次数一样多。我认为您对 merge 的使用可能没有达到您的预期,因为您没有按照您的想法提供合并(它不只是坐在那里等待所有“已获取”对象,然后一次合并它们)。
-
问题是否不清楚? :) 我不知道该怎么做,而且必须有比我刚刚发布的初步答案更好的方法。请注意,这只是一个简单的示例,我需要为我的用例提供一个好的解决方案,可以提炼到这个示例问题(我认为)... take(50).something() 应该能够将所有返回的 observable 合并为一个不知何故,但什么是东西()?
标签: javascript node.js rxjs5 angular2-observables