web-dev-qa-db-ja.com

RxJS Observableが配列を返し、配列の反復ごとに別の関数を実行します

基本的にangularのhttp.getリクエストを返す関数getNews()があります。リクエストの結果はIDの配列です。取得したこの配列を反復処理して、別のhttp.getリクエスト(function getItem(id))を実行します。これにより、サーバーから受信した単一のIDのオブジェクトが返されます。

私はそれを次のように使ってみました:

_  getLatest() {
    return this.http.get('all_news_url')
    .map(res => res.json())
    // I even tried creating Observable from array and get only 5 elements
    //.map(res => Observable.from(res.json()))
    //.take(5)
    .map((data) => this.getItem(data))
    .subscribe(
      data => {
        console.log(data);
      }
    )
  }

  getItem(itemId: any): Observable<any> {
    console.log('item id', itemId);

    return this.http.get(this.generateUrl(`item/${itemId}`))
    .map(res => res.json());
  }
_

明らかに、これは機能しません。 getItem()関数へのパラメーターは、常にIDの配列全体として渡されます。

この質問に参加してくれてありがとう。

7
gregor

Mapの代わりにconcatMap演算子を使用することをお勧めします。 concatMapは、返されるObservableをソースのObservableにフラット化し、mapはobservableのobservableを返します。

GetItem()からのデータを「all_news_url」にリストされているのと同じ順序にしたい場合は、次のような方法を試すことができます。

this.http.get('all_news_url')
.concatMap(res => Observable.from(res.json()).take(5))
.concatMap((data) => this.getItem(data))
.subscribe(
  data => {
    console.log(data);
  }
);

上記のコードでは、getItem()の呼び出しは同期されます。つまり、「item/$ {itemId}」へのリクエストは一度に1つだけです。

順序を気にせず、一度に複数のリクエストを送信してスピードを上げたい場合は、2番目のconcatMapをmergeMapに変更してください。 (item/itemIdへの)リクエストは引き続き順序付けられますが、応答の順序についての保証はありません。最大同時リクエスト数をthirdパラメーターとしてmergeMapに指定できます(undefinedまたはnullを渡すことで2番目のパラメーターを無視します)。

.concatMap(res => Observable.from(res.json()).take(5))
.mergeMap((data) => this.getItem(data), null, 3)

mergeMapの3番目のパラメーターとして1を渡すことは、concatMapと同等です。

11
Can Nguyen