我以正常方式消耗了RxJS序列......
但是,在可观察的'onNext'处理程序中,某些操作将同步完成,但其他操作需要异步回调,需要在处理输入序列中的下一项之前等待。
......有点困惑如何做到这一点。有任何想法吗?谢谢!
someObservable.subscribe(
function onNext(item)
{
if (item == 'do-something-async-and-wait-for-completion')
{
setTimeout(
function()
{
console.log('okay, we can continue');
}
, 5000
);
}
else
{
// do something synchronously and keep on going immediately
console.log('ready to go!!!');
}
},
function onError(error)
{
console.log('error');
},
function onComplete()
{
console.log('complete');
}
);
答案 0 :(得分:24)
您要执行的每个操作都可以建模为可观察的。甚至同步操作也可以这种方式建模。然后,您可以使用map
将序列转换为序列序列,然后使用concatAll
展平序列。
someObservable
.map(function (item) {
if (item === "do-something-async") {
// create an Observable that will do the async action when it is subscribed
// return Rx.Observable.timer(5000);
// or maybe an ajax call? Use `defer` so that the call does not
// start until concatAll() actually subscribes.
return Rx.Observable.defer(function () { return Rx.Observable.ajaxAsObservable(...); });
}
else {
// do something synchronous but model it as an async operation (using Observable.return)
// Use defer so that the sync operation is not carried out until
// concatAll() reaches this item.
return Rx.Observable.defer(function () {
return Rx.Observable.return(someSyncAction(item));
});
}
})
.concatAll() // consume each inner observable in sequence
.subscribe(function (result) {
}, function (error) {
console.log("error", error);
}, function () {
console.log("complete");
});
回复你的一些评论...在某些时候你需要对功能流强制一些期望。在大多数语言中,当处理可能异步的函数时,函数签名是异步的,函数的实际异步与同步性质被隐藏为函数的实现细节。无论您使用的是javaScript promises,Rx observables,c#Tasks,c ++ Futures等,都是如此。函数最终返回promise / observable / task / future / etc,如果函数实际上是同步的,那么它返回的对象是刚刚完成。
话虽如此,因为这是JavaScript,你可以作弊:
var makeObservable = function (func) {
return Rx.Observable.defer(function () {
// execute the function and then examine the returned value.
// if the returned value is *not* an Rx.Observable, then
// wrap it using Observable.return
var result = func();
return result instanceof Rx.Observable ? result: Rx.Observable.return(result);
});
}
someObservable
.map(makeObservable)
.concatAll()
.subscribe(function (result) {
}, function (error) {
console.log("error", error);
}, function () {
console.log("complete");
});
答案 1 :(得分:4)
首先,将异步操作移出subscribe
,不是为了进行异步操作。
您可以使用的是mergeMap
(别名flatMap
)或concatMap
。我提到它们两个,因为concatMap
实际上是mergeMap
且concurrent
参数设置为1.这很有用,因为有时你会想要限制并发查询的数量,但是仍然运行几个。
source.concatMap(item => {
if (item == 'do-something-async-and-wait-for-completion') {
return Rx.Observable.timer(5000)
.mapTo(item)
.do(e => console.log('okay, we can continue'));
} else {
// do something synchronously and keep on going immediately
return Rx.Observable.of(item)
.do(e => console.log('ready to go!!!'));
}
}).subscribe();
我还将展示如何限制通话费率。 建议提示: 仅限实际需要时的速率限制,例如调用仅允许每秒或几分钟的特定数量请求的外部API。否则最好只限制并发操作的数量,让系统以最大速度移动。
我们从以下代码段开始:
const concurrent;
const delay;
source.mergeMap(item =>
selector(item, delay)
, concurrent)
接下来,我们需要为concurrent
,delay
选择值并实施selector
。 concurrent
和delay
密切相关。例如,如果我们想要每秒运行10个项目,我们可以使用concurrent = 10
和delay = 1000
(毫秒),还可以使用concurrent = 5
和delay = 500
或concurrent = 4
和delay = 400
。每秒的商品数量始终为concurrent / (delay / 1000)
。
现在让我们实现selector
。我们有几个选择。我们可以为selector
设置一个最小的执行时间,我们可以为它添加一个恒定的延迟,我们可以在它们可用时立即发出结果,我们可以在最小延迟通过后发出结果等。甚至可以使用timeout
运算符添加超时。便利性。
设置最短时间,尽早发送结果:
function selector(item, delay) {
return Rx.Observable.of(item)
.delay(1000) // replace this with your actual call.
.merge(Rx.Observable.timer(delay).ignoreElements())
}
设置最短时间,迟到发送结果:
function selector(item, delay) {
return Rx.Observable.of(item)
.delay(1000) // replace this with your actual call.
.zip(Rx.Observable.timer(delay), (item, _))
}
添加时间,尽早发送结果:
function selector(item, delay) {
return Rx.Observable.of(item)
.delay(1000) // replace this with your actual call.
.concat(Rx.Observable.timer(delay).ignoreElements())
}
添加时间,迟到发送结果:
function selector(item, delay) {
return Rx.Observable.of(item)
.delay(1000) // replace this with your actual call.
.delay(delay)
}
答案 2 :(得分:0)
进行手动异步操作的另一个简单示例。
请注意,这不是一个好的反应练习!如果您只想等待1000毫秒,请使用Rx.Observable.timer或延迟运算符。
someObservable.flatMap(response => {
return Rx.Observable.create(observer => {
setTimeout(() => {
observer.next('the returned value')
observer.complete()
}, 1000)
})
}).subscribe()
现在,用异步函数替换setTimeout,比如Image.onload或fileReader.onload ......