我有许多与rest服务请求相关的服务,我想缓存从服务器接收到的数据以供进一步使用。 请问有什么最好的方式来缓存响应?
我有许多与rest服务请求相关的服务,我想缓存从服务器接收到的数据以供进一步使用。 请问有什么最好的方式来缓存响应?
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
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)
的另一种广泛使用的方法可以在这里找到。
针对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>
只是我个人的观点,使用 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();
}
}