What is the correct way to share the result of an Angular Http network call in RxJs 5?

前端 未结 21 1743
广开言路
广开言路 2020-11-21 06:11

By using Http, we call a method that does a network call and returns an http observable:

getCustomer() {
    return          


        
21条回答
  •  后悔当初
    2020-11-21 06:20

    UPDATE: Ben Lesh says the next minor release after 5.2.0, you'll be able to just call shareReplay() to truly cache.

    PREVIOUSLY.....

    Firstly, don't use share() or publishReplay(1).refCount(), they are the same and the problem with it, is that it only shares if connections are made while the observable is active, if you connect after it completes, it creates a new observable again, translation, not really caching.

    Birowski gave the right solution above, which is to use ReplaySubject. ReplaySubject will caches the values you give it (bufferSize) in our case 1. It will not create a new observable like share() once refCount reaches zero and you make a new connection, which is the right behavior for caching.

    Here's a reusable function

    export function cacheable(o: Observable): Observable {
      let replay = new ReplaySubject(1);
      o.subscribe(
        x => replay.next(x),
        x => replay.error(x),
        () => replay.complete()
      );
      return replay.asObservable();
    }
    

    Here's how to use it

    import { Injectable } from '@angular/core';
    import { Http } from '@angular/http';
    import { Observable } from 'rxjs/Observable';
    import { cacheable } from '../utils/rxjs-functions';
    
    @Injectable()
    export class SettingsService {
      _cache: Observable;
      constructor(private _http: Http, ) { }
    
      refresh = () => {
        if (this._cache) {
          return this._cache;
        }
        return this._cache = cacheable(this._http.get('YOUR URL'));
      }
    }
    

    Below is a more advance version of the cacheable function This one allows has its own lookup table + the ability to provide a custom lookup table. This way, you don't have to check this._cache like in the above example. Also notice that instead of passing the observable as the first argument, you pass a function which returns the observables, this is because Angular's Http executes right away, so by returning a lazy executed function, we can decide not to call it if it's already in our cache.

    let cacheableCache: { [key: string]: Observable } = {};
    export function cacheable(returnObservable: () => Observable, key?: string, customCache?: { [key: string]: Observable }): Observable {
      if (!!key && (customCache || cacheableCache)[key]) {
        return (customCache || cacheableCache)[key] as Observable;
      }
      let replay = new ReplaySubject(1);
      returnObservable().subscribe(
        x => replay.next(x),
        x => replay.error(x),
        () => replay.complete()
      );
      let observable = replay.asObservable();
      if (!!key) {
        if (!!customCache) {
          customCache[key] = observable;
        } else {
          cacheableCache[key] = observable;
        }
      }
      return observable;
    }
    

    Usage:

    getData() => cacheable(this._http.get("YOUR URL"), "this is key for my cache")
    

提交回复
热议问题