How to correctly retrieve and cache data in Angular service

后端 未结 3 1806
南旧
南旧 2021-01-29 02:29

Frequently, in angular app, i have some service, which need to retreive some data through http request and share it to consumers through BehaviorSubject. It have implementation

相关标签:
3条回答
  • 2021-01-29 02:50

    What about initializing a stream in the constructor that is made hot by an initial call to getData? Then the first result is cached in the ReplaySubject

    class Service {
    
      private init = new Subject();
    
      private data = new ReplaySubject(1);
    
      constructor() {
        this.init.pipe(
          take(1),
          switchMap(() => anyHttpCall())
        )
        .subscribe(res => this.data.next(res));   
      }
    
      getData() {
        this.init.next();
    
        return this.data.asObservable();   
      } 
    }
    
    0 讨论(0)
  • 2021-01-29 03:03

    The best way is using rxjs shareReplay. This operator returns an Observable that shares a single subscription to the underlying source. In other words, turns our observable hot.

    const CACHE_SIZE = 1;
    class Service { 
    
      private _data$: Observable<YourType>;
    
      get data(): Observable<YourType> {
        if (!this._data$) {
          this._data$ = anyHttpCall()
            .pipe(shareReplay({ refCount: true, bufferSize: CACHE_SIZE })
          );
        }
        return this._data$;
      }
    }
    

    The bufferSize determines the maximum element count of the replay buffer, that is the number of elements that are cached and replayed for every subscriber.

    This post explains this very good: https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.html

    0 讨论(0)
  • 2021-01-29 03:08

    What about your options:

    1) Should work but as for me it requires a lot of code written by hand.

    2) Imagine user won't call getData method but you have already sent redundant request.


    There is a very convenient operator shareReplay that will help you make your cold observable hot.

    import { Observable } from 'rxjs';
    import { shareReplay } from 'rxjs/operators';
    
    
    export class Service {
      private cache$: Observable<any>;
      ...
      getData() {
        if (!this.cache$) {
          this.cache$ = this.anyHttpCall().pipe(
            shareReplay(1)
          );
        }
    
        return this.cache$;
      }
    }
    

    Ng-run Example

    0 讨论(0)
提交回复
热议问题