Angular - 缓存http响应的最佳方式

15

我有许多与rest服务请求相关的服务,我想缓存从服务器接收到的数据以供进一步使用。 请问有什么最好的方式来缓存响应?


在HttpClient文档中有一个关于缓存的部分。你到目前为止尝试了什么?哪些方法对你不起作用? - Duncan
谢谢您的回复! - S.Kos
5个回答

7
你可以在这里找到多个答案:Angular 2缓存可观察的HTTP结果数据 我建议构建一个简单的Cacheable<>类,帮助管理从HTTP服务器或其他任何来源检索的数据缓存:
declare type GetDataHandler<T> = () => Observable<T>;

export class Cacheable<T> {

    protected data: T;
    protected subjectData: Subject<T>;
    protected observableData: Observable<T>;
    public getHandler: GetDataHandler<T>;

    constructor() {
      this.subjectData = new ReplaySubject(1);
      this.observableData = this.subjectData.asObservable();
    }

    public getData(): Observable<T> {
      if (!this.getHandler) {
        throw new Error("getHandler is not defined");
      }
      if (!this.data) {
        this.getHandler().map((r: T) => {
          this.data = r;
          return r;
        }).subscribe(
          result => this.subjectData.next(result),
          err => this.subjectData.error(err)
        );
      }
      return this.observableData;
    }

    public resetCache(): void {
      this.data = null;
    }

    public refresh(): void {
      this.resetCache();
      this.getData();
    }

}

用法

声明Cacheable<>对象(可能作为服务的一部分):

list: Cacheable<string> = new Cacheable<string>();

和处理程序:

this.list.getHandler = () => {
// get data from server
return this.http.get(url)
.map((r: Response) => r.json() as string[]);
}

从组件中调用:

//gets data from server
List.getData().subscribe(…)

更多细节和代码示例在这里:http://devinstance.net/articles/20171021/rxjs-cacheable


感谢您在回答中发布链接。 - Chris Claude

3
最简单的缓存服务内部数据的方法是使用shareReplay()函数。

example.service.ts

import { shareReplay } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';

@Injectable({providedIn: 'root'})
export class ExampleService {

    private readonly _data: Observable<IExampleModel[]>;

    constructor(private readonly http: HttpClient) {
        this._data = 
            this.http.get<IExampleModel[]>('/api/example-entities/')
                .pipe(shareReplay());
        }
        
    getExampleEntities() : Observable<IExampleModel[]> {
        return this._data;
    }
}

使用ReplaySubject<T>(1)的另一种广泛使用的方法可以在这里找到。


2

0

针对GET响应,您可以尝试使用这个Get Shell组件,它非常易于使用并设置缓存配置。 ngx-http-get-shell

<ngx-http-get-shell [url]="url" [maxStale]="1000" [templateRef]="tmpl">
  <ng-template #tmpl let-data>
    {{ data | json }}
  </ng-template>
</ngx-http-get-shell>

0

只是我个人的观点,使用 ReplaySubject 和 race

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

import { race, ReplaySubject, tap } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class RandomNumberService {
  constructor(private http: HttpClient) {}

  #number$ = this.newCache;

  private get newCache() {
    return new ReplaySubject<number>(1);
  }

  clearCache() {
    this.#number$ = this.newCache;
  }

  getNumber() {
    return this.http
      .get<{ number: number }>(
        '/api/random-number'
      )
      .pipe(map(({ number }) => number));
  }

  getNumberCachedVersion() {
    return race(
      this.#number$,
      this.getNumber().pipe(tap((number) => this.#number$.next(number)))
    );
  }

  getNumberCachedVersionWithRefreshParameter(refresh: boolean = false) {
    if (refresh) {
      this.clearCache();
    }

    return this.getNumberCachedVersion();
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接