我正在研究记录来自队列的数据。很容易将队列处理成Observable,这样我的代码中就可以有多个端点接收队列中的信息。
此外,我可以确定信息按顺序到达。由于Observables确保这一点,所以这一点也能很好地工作。 但是,一个棘手的问题是我不希望Observer在完成处理前一个事情之前被通知下一件事。但Observer完成的处理是异步的。
作为一个更具体的例子,可能很容易遵循。想象一下,我的队列包含URL。我在我的代码中将它们暴露为Observable。我订阅了一个Observer,它的工作是获取URL并将内容写入磁盘(这是一个人为的例子,因此不要对这些细节产生问题)。重要的是获取和保存是异步的。我的问题是,我不希望观察者从Observable获得“下一个”URL,直到他们完成上一次处理。
但Observer接口上对next
的调用返回void
。因此,Observer无法与实际完成异步任务的人进行通信。
有什么建议吗?我怀疑可能有某种类型的运算符可以编码,它基本上会保留未来的值(在内存中将它们排队?),直到它以某种方式知道Observer已准备就绪。但我希望在一些既定的模式之后已存在类似的事情。
答案 0 :(得分:1)
之前碰到的类似用例
window.document.onkeydown=(e)=>{
return false
}
let count=0;
let asyncTask=(name,time)=>{
time=time || 2000
return Rx.Observable.create(function(obs) {
setTimeout(function() {
count++
obs.next('task:'+name+count);
console.log('Task:',count ,' ', time, 'task complete')
obs.complete();
}, time);
});
}
let subject=new Rx.Subject()
let queueExec$=new Rx.Subject()
Rx.Observable.fromEvent(btnA, 'click').subscribe(()=>{
queueExec$.next(asyncTask('A',4000))
})
Rx.Observable.fromEvent(btnB, 'click').subscribe(()=>{
queueExec$.next(asyncTask('B',4000))
})
Rx.Observable.fromEvent(btnC, 'click').subscribe(()=>{
queueExec$.next(asyncTask('C',4000))
})
queueExec$.concatMap(value=>value)
.subscribe(function(data) {
console.log('onNext', data);
},
function(error) {
console.log('onError', error);
},function(){
console.log('completed')
});
答案 1 :(得分:1)
你所描述的听起来像“背压”。您可以在RxJS 4文档https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/backpressure.md中阅读相关内容。然而,这提到了RxJS 5中不存在的运算符。例如,看一下应该引用你需要的“受控Observables”。
我认为您可以使用concatMap
和主题实例
const asyncOperationEnd = new Subject();
source.concatMap(val => asyncOperationEnd
.mapTo(void 0)
.startWith(val)
.take(2) // that's `val` and the `void 0` that ends this inner Observable
)
.filter(Boolean) // Always ignore `void 0`
.subscribe(val => {
// do some async operation...
// call `asyncOperationEnd.next()` and let `concatMap` process another value
});
你的描述实际上看起来像是“观察者”你提到像Subject一样的作品,所以制作一个你可以在任何Observable链中使用的自定义Subject类会更有意义。
答案 2 :(得分:0)
这不仅仅是concatMap
吗?
// Requests are coming in a stream, with small intervals or without any.
const requests=Rx.Observable.of(2,1,16,8,16)
.concatMap(v=>Rx.Observable.timer(1000).mapTo(v));
// Fetch, it takes some time.
function fetch(query){
return Rx.Observable.timer(100*query)
.mapTo('!'+query).startWith('?'+query);
}
requests.concatMap(q=>fetch(q));
如果要同时允许多次提取,请将mergeMap
与并发参数一起使用。