写在前面

这篇文章其实是 05. 如何从零开始封装 Axios 请求 的续集,在上一篇文章中讲了如何从零封装一个 Axios 请求,这次是对请求功能的补充,增加缓存功能,避免相同的请求多次请求服务器。

在项目中遇到了同一个页面中有多个表格,每个表格都需要重复请求同一个接口的请求而且传参都一样,为了避免在极短时间内重复请求,使用浏览器中的缓存中的上次的值,上次的值在指定时间内自动清除,再次请求时不再请求接口,直接返回缓存的值。

  • 适配器模式
  • 轮询,为什么要添加轮询。不轮询,没有返回数据,还是会发起请求。
  • Map 集合,存储唯一值。
  • 取消后续请求或只有最后一次请求

拦截器vs适配器

Axios 中拦截器和适配器有什么区别,要怎么选择。

具体实现

首先创建一个axiosCacheAdapter.js文件:

import axios from 'axios';
 
const cache = new Map();
const EXPIRATION_TIME_MS = 1 * 1000; // 缓存过期时间(例如:1 秒)
 
// 轮询检查是否有数据
function checking(callback, validate) {
  setTimeout(() => {
      const res = validate && validate()
      if(res) {
        callback && callback(res)
      } else  {
        checking(callback, validate)
      }
  }, 200);
}
 
function CacheValue(response = null) {
  return {
    timestamp: Date.now(),
    response,
  }
}
 
const cacheAdapterEnhancer = config => {
  const { url, method, params, data } = config;
  const cacheKey = JSON.stringify({ url, method, params, data });
 
  if (cache.has(cacheKey)) {
    let cachedResult = cache.get(cacheKey);
    if (Date.now() - cachedResult.timestamp < EXPIRATION_TIME_MS) {
      return new Promise((resolve) => {
        const validate = () => {
          const cachedResult = cache.get(cacheKey);
          return cachedResult.response;
        }
        const callback = (res) => {
          resolve(res);
        }
        checking(callback, validate)
      });
    } else {
      cache.delete(cacheKey);
    }
  }
 
  cache.set(cacheKey, CacheValue());
 
  return axios.defaults.adapter(config).then((response) => {
    cache.set(cacheKey, CacheValue(response));
    return response;
  });
};
 
export default cacheAdapterEnhancer;

注意❗

注意上面代码的 axios 版本为 0.19.0 , 其他版本可能会报错 axios.defaults.adapter not function。新的版本,如1.7.9,有多种默认adapter,需要通过 axios.getAdapter(axios.defaults.adapter[0])(config) 获取默认adapter。

然后在主应用中引入并使用这个适配器:

import axios from 'axios';
import cacheAdapterEnhancer from './axiosCacheAdapter';
 
// 创建axios实例并配置缓存适配器
const instance = axios.create({
  adapter: cacheAdapterEnhancer,
});
 
// 使用自定义的axios实例发送请求
instance.get('/your-api-endpoint', { params: yourParams })
.then(response => {
 console.log(response.data);
})
.catch(error => {
 console.error(error);
});

扩展阅读