- 背景:项目页面使用的组件会自调用请求,同一个页面重复使用了很多这个组件,导致发送了大量相同的请求。
- 解决思路:缓存相同的接口请求结果。遇到相同接口,相同参数的请求,就从缓存直接拿结果。
- 代码实现
import _ from 'lodash-es';
/**
* 缓存接口数据
*/
class CacheAPI {
map = new Map();
// 防止和参数冲突
symbolApi = Symbol('api');
/**
* 组合KEY
* @param api
* @param param
* @returns {{symbolApi: string}}
*/
// eslint-disable-next-line class-methods-use-this
createKey(api = '', param = {}) {
return { [this.symbolApi]: api, ...param };
}
/**
* 发起请求,请求中,命中请求结果
* @param api
* @param param
* @param axioxFn
* @param resolve
*/
// eslint-disable-next-line default-param-last
sendHttpRequst(api = '', param = {}, axioxFn, resolve) {
const KEY = this.createKey(api, param);
// console.log('>>> KEY', KEY, this.map);
// window.__map = this.map;
// 有缓存
if (this.hasApiRequst(KEY)) {
const value = this.getMapValueReslut(KEY);
value.hotNum += 1;
if (value.reslut) {
resolve(value.reslut);
this.checkOutMapMaxToRemove();
} else {
value.promis.push(resolve);
}
} else {
this.initApi(KEY, resolve);
axioxFn().then((res) => {
this.addResult(KEY, res);
});
}
}
/**
* 添加响应结果,并且返回所有完全相同接口的数据
* @param KEY
* @param reslut
*/
addResult(KEY, reslut) {
for (const item of this.map) {
if (_.isEqual(item[0], KEY)) {
const value = item[1];
value.reslut = reslut;
value.promis.forEach((resolv) => {
resolv(value.reslut);
});
value.promis = [];
}
}
}
/**
* 是否有发起过一样的请求【可能在请求中】
* @param KEY
* @returns {boolean}
*/
hasApiRequst(KEY) {
let flag = false;
for (const item of this.map) {
if (_.isEqual(item[0], KEY)) {
flag = true;
}
}
return flag;
}
/**
* 获取某个命中的请求map项
* @param api
* @param param
*/
getMapValueReslut(KEY) {
let value = {};
for (const item of this.map) {
if (_.isEqual(item[0], KEY)) {
value = item[1];
}
}
return value;
}
/**
* 清空 Map
* 切换路由调用
*/
clearMap() {
this.map.clear();
}
/**
* 超过设置缓存最大数,就清除热度较低的缓存
* 最大100个
*/
checkOutMapMaxToRemove() {
if (this.map.size > 100) {
for (const item of this.map) {
if (item[1].hotNum === 1) {
this.map.delete(item[0]);
}
}
}
}
/**
* 创建无相关KEY的请求数据结构
* @param key
* @param resolve
*/
// eslint-disable-next-line class-methods-use-this
initApi(KEY, resolve) {
const value = {
reslut: null, // api返回的结果
promis: [], // resove 集合
hotNum: 1, // 热度
};
value.promis.push(resolve);
this.map.set(KEY, value);
}
}
export default new CacheAPI();
- 使用
import cacheAPI from '@/util/CacheAPI.js';
export const getUserList = (params = {}) => {
const API = '/xxxx/api';
return new Promise((resolve) => {
const axioxFn = () =>
request({
url: API,
method: 'get',
params: {
...params,
},
});
cacheAPI.sendHttpRequst(API, params, axioxFn, resolve);
});
};
- 在合适的时机要调用一下 clearMap,防止内存爆了