缓存与重复请求优化

在大型前端项目中,频繁请求相同接口可能导致性能下降和不必要的网络流量。 Axios 提供了多种方式结合缓存策略与请求去重,优化前端性能。

一、为什么需要缓存与请求去重

  • 减少相同接口的重复请求,降低服务器压力。
  • 提升用户体验,尤其是在慢网或移动端。
  • 避免多次重复请求导致的数据冲突或界面闪烁。

二、浏览器缓存机制

  1. 利用 HTTP 缓存头:

    • Cache-Control:控制缓存策略,如 max-ageno-cache
    • ETag:资源标识符变化时更新缓存。
    • Last-Modified:资源修改时间。
  2. Axios 可结合 If-None-Match / If-Modified-Since 头实现条件请求:

axios.get('/api/data', {
  headers: {
    'If-None-Match': cachedETag
  }
});

三、内存缓存(前端请求去重)

使用简单对象或 Map 缓存请求结果:

const cache = new Map();

async function fetchWithCache(url) {
  if (cache.has(url)) {
    return cache.get(url);
  }
  const response = await axios.get(url);
  cache.set(url, response);
  return response;
}

四、结合拦截器实现全局缓存

const cacheStore = new Map();

axios.interceptors.request.use(config => {
  const key = config.url + JSON.stringify(config.params || {});
  if (cacheStore.has(key)) {
    config.adapter = () => {
      return Promise.resolve(cacheStore.get(key));
    };
  }
  return config;
});

axios.interceptors.response.use(response => {
  const key = response.config.url + JSON.stringify(response.config.params || {});
  cacheStore.set(key, response);
  return response;
});

五、防止重复请求

  • 对同一 URL 和参数的请求,在前一个未完成时阻止再次发送。
const pending = new Map();

function requestWithDedup(config) {
  const key = config.url + JSON.stringify(config.params || {});
  if (pending.has(key)) {
    return pending.get(key);
  }
  const request = axios(config).finally(() => pending.delete(key));
  pending.set(key, request);
  return request;
}

六、缓存过期与更新策略

  • 可设置时间戳过期:
const cache = new Map();

function fetchWithExpiry(url, ttl = 5000) {
  const now = Date.now();
  const cached = cache.get(url);
  if (cached && (now - cached.time < ttl)) {
    return Promise.resolve(cached.response);
  }
  return axios.get(url).then(res => {
    cache.set(url, { response: res, time: now });
    return res;
  });
}
  • 支持手动清理或基于版本号更新缓存。

七、小结

优化缓存和防止重复请求,可以显著提升前端性能与用户体验。 最佳实践:

  • 静态数据优先使用浏览器缓存。
  • 动态数据结合内存缓存和请求去重。
  • 使用拦截器统一管理缓存逻辑。
  • 对幂等请求安全重试,对非幂等请求谨慎。