[英]Wait for an async operation in onNext of RxJS Observable
我有正常方式消耗的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');
}
);
您要執行的每個操作都可以建模為可觀察的。 甚至同步操作也可以這種方式建模。 然后,您可以使用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");
});
首先,將異步操作從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
運算符添加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)
}
另一個做手動異步操作的簡單示例。
請注意,這不是一個好的反應練習! 如果您只想等待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 ......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.