JS之给频繁的请求结果增加缓存

由于后端限制不能频繁请求,所以500ms内的二次请求会返回服务器繁忙,请稍后再试,但是业务需要对同一接口频繁进行多次请求,因此,可以通过给请求结果增加缓存来解决。

request.js修改:增加adapter配置

import axios from 'axios'
import cacheAdapterEnhancer from './axiosCacheAdapter';

// create an axios instance
const service = axios.create({
  adapter: cacheAdapterEnhancer,
  baseURL: import.meta.env.VITE_APP_BASE_API, // api 的 base_url
  withCredentials: true // 跨域请求时发送 cookies
})

axiosCacheAdapter.js:

import axios from "axios";

const cache = new Map();
const EXPIRATION_TIME_MS = 1 * 600; // 缓存过期时间
const cacheKeySet = new Set(); // 处理相同接口同时发起请求

const getCacheValue = (cacheKey) => {
  return poll(() => {
    return cache.get(cacheKey);
  }, 600);
};

const cacheAdapterEnhancer = async (config) => {
  const { url, method, params, data, isCached } = config;
  if (!isCached) {
    return axios.defaults.adapter(config);
  }
  const cacheKey = JSON.stringify({ url, method, params, data });
  if (cacheKeySet.has(cacheKey)) {
    const existing = cache.get(cacheKey);
    // 如果缓存已过期,清除后重新发起请求
    if (existing && Date.now() - existing.timestamp >= EXPIRATION_TIME_MS) {
      cache.delete(cacheKey);
      cacheKeySet.delete(cacheKey);
    } else {
      // 等待相同接口返回缓存(处理真正的并发请求)
      const res = await getCacheValue(cacheKey);
      return Promise.resolve(res?.data);
    }
  }

  // 添加缓存key
  cacheKeySet.add(cacheKey);

  if (cache.has(cacheKey)) {
    const cachedResult = cache.get(cacheKey);
    if (Date.now() - cachedResult.timestamp < EXPIRATION_TIME_MS) {
      return Promise.resolve(cachedResult.data);
    } else {
      cache.delete(cacheKey);
    }
  }

  const response = await axios.defaults.adapter(config);
  const cacheValue = {
    timestamp: Date.now(),
    data: response,
  };
  cache.set(cacheKey, cacheValue);
  setTimeout(() => {
    // 删除缓存key
    cacheKeySet.delete(cacheKey);
  }, 1000);

  return response;
};

function poll(
  fn,
  interval,
  {
    timeout = Infinity,
    maxAttempts = 10,
    onError = null,
    immediate = false,
  } = {}
) {
  let attempts = 0;
  let startTime = Date.now();

  return new Promise((resolve, reject) => {
    const executePoll = async () => {
      try {
        const result = await fn(); // 兼容异步和同步返回值
        if (result) return resolve(result); // 任务成功,结束轮询
      } catch (error) {
        if (onError) onError(error, attempts);
      }

      attempts++;
      if (Date.now() - startTime >= timeout || attempts >= maxAttempts) {
        // 轮询超时或达到最大尝试次数
        return reject(new Error("网络错误,请检查网络后重试"));
      }

      setTimeout(executePoll, interval);
    };

    if (immediate) {
      executePoll(); // 立即执行第一次任务
    } else {
      setTimeout(executePoll, interval);
    }
  });
}

export default cacheAdapterEnhancer;

给需要缓存的接口增加isCached的配置。

// 查询表结构(表头)
getSheetCols(id) {
    return request({
        url: `/field/getSheetCols/${id}`,
        method: 'get',
        isCached: true
    })
}

即可。

posted @ 2025-04-13 12:54  罗毅豪  阅读(64)  评论(0)    收藏  举报