web-dev-qa-db-ja.com

RxJSで2つのオブザーバブルを「待機」する方法

私のアプリには次のようなものがあります:

this._personService.getName(id)
      .concat(this._documentService.getDocument())
      .subscribe((response) => {
                  console.log(response)
                  this.showForm()
       });

 //Output: 
 // [getnameResult]
 // [getDocumentResult]

 // I want:
 // [getnameResult][getDocumentResult]

次に、2つの個別の結果を取得します。最初は_personService、次に_documentServiceです。 this.showForm()を呼び出して終了し、それぞれの結果を操作する前に、両方の結果を待つにはどうすればよいですか。

45
gog

更新:2018年10月

以前にZipメソッドの使用を提案しました。しかし、それ以来、代わりにcombineLatestを使用していることに気付きました。そこで、combineLatestを追加することにしました。

CombineLatestは、オブザーバブルから最新の発行値を発行します。 Zipメソッドは、放出された項目をsequence順序で放出します。

たとえば、オブザーバブル#1がrdアイテムを放出し、オブザーバブル#2が5thアイテムを放出した場合。 Zipメソッドを使用した結果は、両方のobservablesの-​​rd発行値になります。

この場合、combineLatestを使用した結果は5thおよびrdになります。より自然に感じます。


combLatest(オブザーバブル)

ReactiveXから ドキュメント

入力Observableが値を出力するたびに、すべての入力から最新の値を使用して式を計算し、その式の出力を出力します。

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

combineLatest(name$, document$, (name, document) => ({name, document}))
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

Observable.Zip(オブザーバブル)

Observable.Zipメソッドは reactiveX documentation で説明されています:

複数のObservableを組み合わせて、各入力Observableの値から順番に値が計算されるObservableを作成します。

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

Observable
    .Zip(name$, document$, (name: string, document: string) => ({name, document}))
    .subscribe(pair => {
           this.name = pair.name;
           this.document = pair.document;
           this.showForm();
       })

サイドノート(両方の方法に適用)

関数を提供した最後のパラメーター(name: string, document: string) => ({name, document})はオプションです。スキップするか、より複雑な操作を行うことができます。

最新のパラメーターが関数の場合、この関数は入力値から作成された値を計算するために使用されます。それ以外の場合、入力値の配列が返されます。

したがって、最後の部分をスキップすると、配列が取得されます。

// Observables to combine
const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

Observable
    .Zip(name$, document$)
    .subscribe(pair => {
           this.name = pair['0'];
           this.document = pair['1'];
           this.showForm();
       })
57
Hamid Asghari

オブザーバブルのforkJoin()メソッドを使用します。 参照用にこのリンクを確認してください

RXJSから docs

この演算子は、オブザーバブルのグループがあり、それぞれの最終的な放出値のみを考慮する場合に最適です。これの一般的な使用例は、ページの読み込み(または他のイベント)で複数のリクエストを発行し、すべてのレスポンスが受信されたときにのみアクションを実行する場合です。この方法では、 Promise.all を使用する方法に似ています

Observable.forkJoin([character, characterHomeworld]).subscribe(results => {
  // results[0] is our character
  // results[1] is our character homeworld
  results[0].homeworld = results[1];
  this.loadedCharacter = results[0];
});

から取得したコード: https://coryrylan.com/blog/angular-multiple-http-requests-with-rxjs

23
Prathmesh Dali

ダミーのRxJS演算子:forkJoin、Zip、combineLatest、withLatestFrom が非常に役立ちました。名前が示すように、次の組み合わせ演算子を説明します。

それらのいずれかは、場合に応じて、あなたが探しているものになる可能性があります。詳細については、記事を確認してください。

5
nyxz

私にとってこれは sample が最良の解決策でした。

const source = Observable.interval(500);
const example = source.sample(Observable.interval(2000));
const subscribe = example.subscribe(val => console.log('sample', val));

だから.. 2番目(例)が放出するときのみ-最初(ソース)の最後に放出された値が表示されます。

私のタスクでは、フォームの検証と他のDOMイベントを待ちます。

「combineLatest」メソッドを見てください。ここで適切かもしれません。 http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-combineLatest

const { Observable } = Rx

const name$ = this._personService.getName(id);
const document$ = this._documentService.getDocument();

Observable
    .combineLatest(name$, document$, (name, document) => ({ name, document }))
    .first() // or not, implementation detail
    .subscribe(({ name, document }) => {
        // here we have both name and document
        this.showForm()
    })
1
Tal

次のように「Zip」または「buffer」を使用できます。

function getName() {
    return Observable.of('some name').delay(100);
}

function getDocument() {
    return Observable.of('some document').delay(200);
}

// CASE1 : concurrent requests
Observable.Zip(getName(), getDocument(), (name, document) => {
    return `${name}-${document}`;
})
    .subscribe(value => console.log(`concurrent: ${value}`));

// CASE2 : sequential requests
getName().concat(getDocument())
    .bufferCount(2)
    .map(values => `${values[0]}-${values[1]}`)
    .subscribe(value => console.log(`sequential: ${value}`));
0
thatseeyou