通常の方法で消費されるRxJSシーケンスがあります...
ただし、observable '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 promise、Rx observables、c#Tasks、c ++ Futuresなどを使用している場合に当てはまります。関数は最終的にpromise/observable/task/future/etcを返し、関数が実際に同期している場合、それが返すオブジェクトはすでに完了しました。
とは言っても、これはJavaScriptなので、canカンニング:
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
パラメーターが1に設定されたconcurrent
です)同時クエリの数を制限しますが、それでもいくつかの同時クエリを実行します。
_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();
_
また、通話をレート制限する方法も示します。 アドバイス: 1秒または1分あたり特定の数のリクエストのみを許可する外部API。それ以外の場合は、同時操作の数を制限し、システムを最大速度で移動させることをお勧めします。
次のスニペットから始めます。
_const concurrent;
const delay;
source.mergeMap(item =>
selector(item, delay)
, concurrent)
_
次に、concurrent
、delay
の値を選択し、selector
を実装する必要があります。 concurrent
とdelay
は密接に関連しています。たとえば、1秒間に10個のアイテムを実行する場合、_concurrent = 10
_および_delay = 1000
_(ミリ秒)を使用できますが、_concurrent = 5
_および_delay = 500
_または_concurrent = 4
_も使用できますおよび_delay = 400
_。 1秒あたりのアイテム数は常に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)
}
_
手動の非同期操作を行う別の簡単な例。
それは良いリアクティブな実践ではないことに注意してください! 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などの非同期関数に置き換えます...