Sim*_*gro 5 javascript rxjs typescript angular
我想通过共享可观察对象来缓存 HTTP 并行请求,并将响应缓存在 Map 对象中。
缓存interceptor.service.ts
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { tap, finalize, share } from 'rxjs/operators';
@Injectable()
export class CachingInterceptorService implements HttpInterceptor {
public readonly store = new Map<string, HttpResponse<any>>();
public readonly queue = new Map<string, Observable<HttpEvent<any>>>();
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Don't cache if it's not cacheable
if ( req.method !== 'GET' ) {
return next.handle(req);
}
// Checked if there is pending response for this request
const cachedObservable: Observable<HttpEvent<any>> = this.queue.get(req.urlWithParams);
if ( cachedObservable ) {
console.info('Observable cached');
return cachedObservable;
}
// Checked if there is cached response for this request
const cachedResponse: HttpResponse<any> = this.store.get(req.urlWithParams);
if (cachedResponse) {
console.info('Response cached');
return of(cachedResponse.clone());
}
// If the request of going through for first time
// then let the request proceed and cache the response
console.info('Request execute');
const shared = next.handle(req).pipe(
tap(event => {
if (event instanceof HttpResponse) {
console.info('Response reached');
this.store.set(req.urlWithParams, event.clone());
}
}),
finalize(() => {
// delete pending request
this.queue.delete(req.urlWithParams);
}),
share()
);
// add pending request to queue for cache parallell request
this.queue.set(req.urlWithParams, shared);
return shared;
}
}
Run Code Online (Sandbox Code Playgroud)
这种可观察缓存的实现是否正确?
我有些怀疑:如果 observable 被删除到请求的最终确定中并且有些人已经订阅了会发生什么?
旁注:这只是一个例子,并没有实现缓存过期/失效。
您的实现工作正常,但我认为它可以变得更简单。
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { shareReplay, first, filter } from 'rxjs/operators';
@Injectable()
export class CachingInterceptorService implements HttpInterceptor {
public readonly store: Record<string, Observable<HttpEvent<any>>> = {};
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Don't cache if it's not cacheable
if ( req.method !== 'GET' ) {
return next.handle(req);
}
// Check if observable is in cache, otherwise call next.handle
const cachedObservable = this.store[req.urlWithParams] ||
( this.store[req.urlWithParams] = next.handle(req).pipe(
// Filter since we are interested in caching the response only, not progress events
filter((res) => res instanceof HttpResponse ),
// Share replay will cache the response
shareReplay(1),
));
// pipe first() to cause the observable to complete after it emits the response
// This mimics the behaviour of Observables returned by Angular's httpClient.get()
// And also makes toPromise work since toPromise will wait until the observable completes.
return cachedObservable.pipe(first());
}
}
Run Code Online (Sandbox Code Playgroud)
检查我的Stackblitz 叉子
| 归档时间: |
|
| 查看次数: |
1147 次 |
| 最近记录: |