关于请求缓存之连续请求缓存不上问题的解决方案

背景

我目前参与的这个项目有点像是低代码平台,由于是公司产品,我不便透露,我们只用关心我是需要去请求一些模型,这个模型只是针对于界面展示形式的一些信息,不涉及数据,但是需要频繁请求,因此这就需要将请求封装一层,将结果缓存,等下次再次请求的时候直接从缓存中拿。这个方案很好的解决了频繁请求统一接口,而这个接口又不涉及实时性的问题时的性能优化。

但是,这样并不能很好的去解决一种情况:
当我同时请求多次一样的接口时,是来不及缓存的(虽然这样做很奇怪,但是我们确实是有这样的需求的)

开发技术:angular16

原因

同一时间请求接口,他们都是异步的,所以第一个接口发送出去之后拿到返回数据时,其他同时发送的接口已经发送过了,甚至于他们的结果同时返回,那么此时就缓存不上了。

尝试

第一个尝试:请求接口时同步化处理。
这个解决方案可能对一些情况下有用,但针对于我目前来说,前面也提过,我这个项目像是一个低代码平台,所以我写的大多都是基础组件类一样的组件,我之所以同时请求多次接口是因为我同时加载这个小组件,就像是表格的toolbar一样。
所以组件与组件之间是做不到同步请求的。

第二次尝试:即时缓存
这是同事帮我实现的一种方法,我get到这个知识点了!
具体实现逻辑是:借助全局服务,在其中创建一个存储的map或者对象,之后可以使用如下代码

  initModel(render: IToolbarRenderParameter): Observable<IToolbarUiModel> {
  	// 请求前先获取缓存
    const obs = this.cachedUiModelMap.get(render['toolbar']!);
    if (obs) {
      // 如果有就拿取缓存内容
      return obs.asObservable();
    } else {
      // 如果没有就进行缓存,同时正常发送请求
      const obs = new BehaviorSubject<IToolbarUiModel>({ name: '' });
      this.cachedUiModelMap.set(render['toolbar']!, obs);
      // 发送请求
      ...(代码省略)
      return obs;
    }
  }

封装

上方的方案是针对于组件内部的,那么拓展之后,如果可以在请求拦截器中做一个几秒内的缓存处理。

import { HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of, takeUntil, timer } from 'rxjs';
import { shareReplay, tap } from 'rxjs/operators';

@Injectable()
export class CacheInterceptor implements HttpInterceptor {
  // 缓存的map
  private cache = new Map();
  // 缓存时间
  private cacheTime = 5000;
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> {
    const key = request.urlWithParams;
	// 可以在请求头里配置,如果有needCache属性为true,就不进行缓存操作,而是直接进行网络请求
    const needCache = request.headers.get('needCache');
    if (needCache) {
      // 去掉这个请求头,不然会报错
      request = request.clone({
        headers: request.headers.delete('needCache')
      });
      // 如果没有缓存的数据或者超过限定时长,就正常请求
      if (!this.cache.has(key) || Date.now() - this.cache.get(key).lastTime > this.cacheTime) {
        const cachTimer$ = timer(this.cacheTime);
        const cachRequest$ = next.handle(request).pipe(
          takeUntil(cachTimer$),
          shareReplay(1),
          tap(event => {
            this.cache.set(key, {
              data: cachRequest$,
              lastTime: Date.now()
            });
          })
        );
        // 在限定时间结束后,清空下缓存
        cachTimer$.subscribe(() => this.cache.delete(key));
        return cachRequest$;
      }
      // 拿取缓存数据
      return this.cache.get(key).data;
    }

    return next.handle(request);
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值