次のように、Observableがあるとします。
var one = someObservable.take(1);
one.subscribe(function(){ /* do something */ });
次に、2番目の観測対象があります。
var two = someOtherObservable.take(1);
ここで、two
にサブスクライブしたいのですが、one
サブスクライバーが起動される前にtwo
が完了したことを確認したいです。 two
でどのようなバッファリング方法を使用して、2番目のメソッドが最初のメソッドが完了するのを待つことができますか?
two
が完了するまで、one
を一時停止しようとしていると思います。
私が考えることができるいくつかの方法
import {take, publish} from 'rxjs/operators'
import {concat} from 'rxjs'
//Method one
var one = someObservable.pipe(take(1));
var two = someOtherObservable.pipe(take(1));
concat(one, two).subscribe(function() {/*do something */});
//Method two, if they need to be separate for some reason
var one = someObservable.pipe(take(1));
var two = someOtherObservable.pipe(take(1), publish());
two.subscribe(function(){/*do something */});
one.subscribe(function(){/*do something */}, null, two.connect.bind(two));
skipUntil:別のオブザーバブルが放出されるまで、放出されたアイテムを無視します
last:シーケンスから最後の値を発行します(つまり、完了するまで待ってから発行します)
skipUntil
に渡されたobservableから放出されたものはすべてスキップをキャンセルするため、ストリームが完了するのを待つためにlast()
-を追加する必要があります。
main$.skipUntil(sequence2$.pipe(last()))
公式: https://rxjs-dev.firebaseapp.com/api/operators/skipUntil
考えられる問題:last()
自体 エラーになる 何も出力されない場合に注意してください。 last()
演算子には、default
パラメーターがありますが、述部と組み合わせて使用する場合のみです。この状況があなたにとって問題であるなら(sequence2$
が発光せずに完了する場合)、これらのいずれかが動作するはずです(現在テストされていません):
main$.skipUntil(sequence2$.pipe(defaultIfEmpty(undefined), last()))
main$.skipUntil(sequence2$.pipe(last(), catchError(() => of(undefined))
undefined
は発行する有効なアイテムですが、実際には任意の値にすることができます。また、これはsequence2$
パイプではなく、main$
に接続されたパイプであることに注意してください。
実行順序が保持されるようにする場合は、flatMapを次の例のように使用できます。
const first = Rx.Observable.of(1).delay(1000).do(i => console.log(i));
const second = Rx.Observable.of(11).delay(500).do(i => console.log(i));
const third = Rx.Observable.of(111).do(i => console.log(i));
first
.flatMap(() => second)
.flatMap(() => third)
.subscribe(()=> console.log('finished'));
結果は次のようになります。
"1"
"11"
"111"
"finished"
SwitchMapの結果セレクターを活用する別の可能性があります
var one$ = someObservable.take(1);
var two$ = someOtherObservable.take(1);
two$.switchMap(
/** Wait for first Observable */
() => one$,
/** Only return the value we're actually interested in */
(value2, value1) => value2
)
.subscribe((value2) => {
/* do something */
});
SwitchMapの結果セレクターは減価償却されているため、ここに更新バージョンがあります
const one$ = someObservable.pipe(take(1));
const two$ = someOtherObservable.pipe(
take(1),
switchMap(value2 => one$.map(_ => value2))
);
two$.subscribe(value2 => {
/* do something */
});
2番目のオブザーバブルがhotの場合、 別の方法 to(pause/resume) :
var pauser = new Rx.Subject();
var source1 = Rx.Observable.interval(1000).take(1);
/* create source and pause */
var source2 = Rx.Observable.interval(1000).pausable(pauser);
source1.doOnCompleted(function () {
/* resume paused source2 */
pauser.onNext(true);
}).subscribe(function(){
// do something
});
source2.subscribe(function(){
// start to recieve data
});
また、バッファ付きバージョンpausableBufferedを使用して、一時停止がオンの間にデータを保持できます。
再利用可能な方法を次に示します(TypeScriptですが、jsに適合させることができます):
export function waitFor<T>(signal: Observable<any>) {
return (source: Observable<T>) =>
new Observable<T>(observer =>
signal.pipe(first())
.subscribe(_ =>
source.subscribe(observer)
)
);
}
そして、あなたは他の演算子のようにそれを使用することができます:
var two = someOtherObservable.pipe(waitFor(one), take(1));
基本的に、シグナルobservableが最初のイベントを発行するまで、ソースobservableのサブスクライブを延期する演算子です。
RxJSに簡単に翻訳できるRxSwiftのかなり直感的でシンプルな実装を次に示します。
Observable.never().takeUntil(signalingObservable).concat(delayedObservable)
mergeMap(または彼のエイリアスflatMap)演算子のおかげで、以前のObservableから出力された結果を次のように使用できます。
const one = Observable.of('https://api.github.com/users');
const two = (c) => ajax(c);//ajax from Rxjs/dom library
one.mergeMap(two).subscribe(c => console.log(c))
まあ、私はこれがかなり古いことを知っていますが、あなたが必要とするかもしれないものは次のとおりだと思います:
var one = someObservable.take(1);
var two = someOtherObservable.pipe(
concatMap((twoRes) => one.pipe(mapTo(twoRes))),
take(1)
).subscribe((twoRes) => {
// one is completed and we get two's subscription.
})