Angular 5缓存http服务api调用

Her*_*sen 11 angular angular-httpclient

在我的Angular 5应用程序中,在应用程序的不同位置需要多次某个数据集(不经常更改).调用API后,结果将与Observable do运算符一起存储.这样我在我的服务中实现了HTTP请求的缓存.

我正在使用Angular 5.1.3和RxJS 5.5.6.

这是一个好习惯吗?还有更好的选择吗?

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/do';

@Injectable()
export class FruitService {

  fruits: Array<string> = [];

  constructor(private http: HttpClient) { }

  getFruits() {
    if (this.fruits.length === 0) {
      return this.http.get<any>('api/getFruits')
        .do(data => { this.fruits = data })
    } else {
      return Observable.of(this.fruits);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

And*_*tar 14

您的解决方案的问题在于,如果第一个呼叫在第一个呼叫到期时出现,则会创建新的http请求.我将如何做到这一点:

@Injectable()
export class FruitService {

  readonly fruits = this.http.get<any>('api/getFruits').shareReplay(1);

  constructor(private http: HttpClient) { }
}
Run Code Online (Sandbox Code Playgroud)

更大的问题是当你有params并且你想根据params缓存.在这种情况下,你需要某种memoize功能,如lodash中的功能(https://lodash.com/docs/4.17.5#memoize)

您还可以cache为其实现一些内存中的运算符Observable,例如:

const cache = {};

function cacheOperator<T>(this: Observable<T>, key: string) {
    return new Observable<T>(observer => {
        const cached = cache[key];
        if (cached) {
            cached.subscribe(observer);
        } else {
            const add = this.multicast(new ReplaySubject(1));
            cache[key] = add;
            add.connect();
            add.catch(err => {
                delete cache[key];
                throw err;
            }).subscribe(observer);
        }
    });
}

declare module 'rxjs/Observable' {
    interface Observable<T> {
        cache: typeof cacheOperator;
    }
}

Observable.prototype.cache = cacheOperator;
Run Code Online (Sandbox Code Playgroud)

并使用它像:

getFruit(id: number) {
  return this.http.get<any>(`api/fruit/${id}`).cache(`fruit:${id}`);
}
Run Code Online (Sandbox Code Playgroud)

  • 缓存运算符是很好的POC,但它不实用.私有缓存存储的无法控制的增长不是IRL的好事.可能还有其他问题,例如最大容量,到期和强制刷新.这应该由缓存服务处理. (2认同)

Laz*_*yee 8

还有另一种方法可以使用 shareReplay 和 Angular 5、6 或 7:创建一个服务:

import { Observable } from 'rxjs/Observable';
import { shareReplay } from 'rxjs/operators';
const CACHE_SIZE = 1;

private cache$: Observable<Object>;

get api() {
  if ( !this.cache$ ) {
    this.cache$ = this.requestApi().pipe( shareReplay(CACHE_SIZE) );
  }
  return this.cache$;
}

private requestApi() {
  const API_ENDPOINT = 'yoururl/';
  return this.http.get<any>(API_ENDPOINT);
}

public resetCache() {
  this.cache$ = null;
}
Run Code Online (Sandbox Code Playgroud)

要直接在 html 文件中读取数据,请使用以下命令:

<div *ngIf="this.apiService.api | async as api">{{api | json}}</div>
Run Code Online (Sandbox Code Playgroud)

在您的组件中,您可以像这样订阅:

this.apiService.api.subscribe(res => {/*your code*/})
Run Code Online (Sandbox Code Playgroud)