如何在Angular服务中正确检索和缓存数据

时间:2018-07-17 18:43:13

标签: angular

通常,在有角度的应用程序中,我有一些服务,需要通过http请求检索一些数据,并通过BehaviorSubject将其共享给消费者。它具有这样的实现:

class Service { 

  private data = new BehaviorSubject();

  getData() {
    if (!this.data.getValue()) {
      anyHttpCall().subscribe(res => this.data.next(res));
    }

    return this.data.asObservable();
  } 
}

这种方法的主要原理是,当应用程序的某些组件在没有值时同时调用getData()时,它将触发多个http调用并发出数据,因此我发现了两种防止它的方法:

1)存储表明请求状态的布尔变量

class Service { 

  private data = new BehaviorSubject();   

  private pendingResult = false;

  getData() {
    if (!this.data.value && !this.pendingResult) {
      this.pendingResult = true;
      anyHttpCall().subscribe(res =>   {
        this.data.next(res);
        this.pendingResult = false;
      }
    }

    return this.data.asObservable();
  } 
}

2)在服务构造函数中获取数据

class Service { 

  private data = new BehaviorSubject();  

  constructor() {
    anyHttpCall().subscribe(resthis.data.next(res));
  }

  getData() {
    return this.data.asObservable();
  } 
}

那么,哪种方法是最好的,为什么?

3 个答案:

答案 0 :(得分:1)

最好的方法是使用rxjs shareReplay 。该运算符返回一个Observable,它共享对基础源的单个订阅。换句话说,使我们的可观察性变得炙手可热。

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$;
  }
}

bufferSize 确定重播缓冲区的最大元素数,即为每个订阅者缓存和重播的元素数。

这篇文章对此做得很好:https://blog.thoughtram.io/angular/2018/03/05/advanced-caching-with-rxjs.html

答案 1 :(得分:0)

如何初始化在构造器中通过初始调用getData而变得很热的流?然后将第一个结果缓存在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();   
  } 
}

答案 2 :(得分:0)

您的选择如何?

1)应该可以,但对我来说,它需要手工编写很多代码。

2)想象用户不会调用getData方法,但是您已经发送了冗余请求。


有一个非常方便的运算符shareReplay,它将帮助您使冷观测变得很热。

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