RxJs 5 で Angular Http ネットワーク呼び出しの結果を共有する正しい方法は何ですか? 質問する

RxJs 5 で Angular Http ネットワーク呼び出しの結果を共有する正しい方法は何ですか? 質問する

Http を使用して、ネットワーク呼び出しを実行し、http オブザーバブルを返すメソッドを呼び出します。

getCustomer() {
    return this.http.get('/someUrl').map(res => res.json());
}

この Observable に複数のサブスクライバーを追加すると、次のようになります。

let network$ = getCustomer();

let subscriber1 = network$.subscribe(...);
let subscriber2 = network$.subscribe(...);

私たちがやりたいのは、これによって複数のネットワーク要求が発生しないようにすることです。

これは珍しいシナリオのように思えるかもしれませんが、実際には非常に一般的です。たとえば、呼び出し元がエラー メッセージを表示するために observable をサブスクライブし、非同期パイプを使用してそれをテンプレートに渡す場合、すでに 2 つのサブスクライバーが存在します。

RxJs 5 でこれを行う正しい方法は何ですか?

つまり、これはうまく動作するようです:

getCustomer() {
    return this.http.get('/someUrl').map(res => res.json()).share();
}

しかし、これは RxJs 5 でこれを行う慣用的な方法でしょうか、それとも代わりに何か他の方法を行うべきでしょうか?

注: Angular 5 の新機能によりHttpClient.map(res => res.json())JSON 結果がデフォルトで想定されるようになったため、すべての例の 部分は役に立たなくなりました。

ベストアンサー1

編集: 2021 年現在、適切な方法は、shareReplayRxJs によってネイティブに提案された演算子を使用することです。詳細については、以下の回答を参照してください。


データをキャッシュし、キャッシュが利用可能な場合はこれを返し、そうでない場合は HTTP リクエストを実行します。

import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of'; //proper way to import the 'of' operator
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
import {Data} from './data';

@Injectable()
export class DataService {
  private url: string = 'https://cors-test.appspot.com/test';
  
  private data: Data;
  private observable: Observable<any>;

  constructor(private http: Http) {}

  getData() {
    if(this.data) {
      // if `data` is available just return it as `Observable`
      return Observable.of(this.data); 
    } else if(this.observable) {
      // if `this.observable` is set then the request is in progress
      // return the `Observable` for the ongoing request
      return this.observable;
    } else {
      // example header (not necessary)
      let headers = new Headers();
      headers.append('Content-Type', 'application/json');
      // create the request, store the `Observable` for subsequent subscribers
      this.observable = this.http.get(this.url, {
        headers: headers
      })
      .map(response =>  {
        // when the cached data is available we don't need the `Observable` reference anymore
        this.observable = null;

        if(response.status == 400) {
          return "FAILURE";
        } else if(response.status == 200) {
          this.data = new Data(response.json());
          return this.data;
        }
        // make it shared so more than one subscriber can get the result
      })
      .share();
      return this.observable;
    }
  }
}

プランカーの例

この記事https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.htmlキャッシュする方法についての優れた説明ですshareReplay

おすすめ記事