前端数据缓存机制详解

前端数据缓存机制是提升应用性能、减少网络请求、优化用户体验的关键技术手段。以下是前端常见的数据缓存方案及其实现细节,涵盖浏览器缓存、本地存储、内存缓存等多种策略:


1. 浏览器缓存(HTTP 缓存)

通过 HTTP 协议头控制缓存,适用于静态资源(如 JS、CSS、图片)和接口响应。

1.1 强缓存
  • 原理:浏览器直接使用本地缓存,不向服务器发送请求。
  • 实现方式
    Cache-Control: max-age=3600  # 资源有效期 1 小时(优先级高)
    Expires: Wed, 21 Oct 2024 07:28:00 GMT  # 过期时间(HTTP/1.0)
    
1.2 协商缓存
  • 原理:浏览器携带缓存标识询问服务器资源是否更新。
  • 实现方式
    # 服务器返回标识
    ETag: "33a64df551425fcc55e4d42a148795d9"
    Last-Modified: Wed, 21 Oct 2024 07:28:00 GMT
    
    # 浏览器请求时携带标识
    If-None-Match: "33a64df551425fcc55e4d42a148795d9"
    If-Modified-Since: Wed, 21 Oct 2024 07:28:00 GMT
    

2. Web Storage

适用于存储结构化数据,容量约 5~10MB,分为 localStoragesessionStorage

2.1 基本使用
// 存储数据(注意:只能存字符串)
localStorage.setItem('user', JSON.stringify({ name: 'Alice' }));

// 读取数据
const user = JSON.parse(localStorage.getItem('user'));

// 删除数据
localStorage.removeItem('user');
2.2 缓存策略示例
async function fetchWithCache(url, cacheKey, ttl = 3600) {
  const cachedData = localStorage.getItem(cacheKey);
  if (cachedData) {
    const { data, timestamp } = JSON.parse(cachedData);
    if (Date.now() - timestamp < ttl * 1000) {
      return data; // 返回有效缓存
    }
  }
  const response = await fetch(url);
  const newData = await response.json();
  localStorage.setItem(cacheKey, JSON.stringify({
    data: newData,
    timestamp: Date.now()
  }));
  return newData;
}

3. IndexedDB

适用于存储大量结构化数据(支持索引、事务),容量可达数百 MB。

3.1 基本操作
// 打开数据库
const request = indexedDB.open('myDB', 1);

request.onupgradeneeded = (event) => {
  const db = event.target.result;
  const store = db.createObjectStore('apiCache', { keyPath: 'url' });
  store.createIndex('timestamp', 'timestamp', { unique: false });
};

// 存储数据
function saveToIndexedDB(url, data) {
  const transaction = db.transaction('apiCache', 'readwrite');
  const store = transaction.objectStore('apiCache');
  store.put({ url, data, timestamp: Date.now() });
}

// 查询数据
async function getFromIndexedDB(url) {
  return new Promise((resolve) => {
    const transaction = db.transaction('apiCache', 'readonly');
    const store = transaction.objectStore('apiCache');
    const request = store.get(url);
    request.onsuccess = (e) => resolve(e.target.result?.data);
  });
}

4. 内存缓存

适用于单页应用(SPA)中短期数据缓存,随页面刷新失效。

4.1 全局变量缓存
const memoryCache = new Map();

async function fetchWithMemoryCache(url) {
  if (memoryCache.has(url)) {
    return memoryCache.get(url);
  }
  const response = await fetch(url);
  const data = await response.json();
  memoryCache.set(url, data);
  return data;
}
4.2 LRU 缓存策略
class LRUCache {
  constructor(maxSize = 100) {
    this.cache = new Map();
    this.maxSize = maxSize;
  }

  get(key) {
    if (!this.cache.has(key)) return null;
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }

  set(key, value) {
    if (this.cache.size >= this.maxSize) {
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }
    this.cache.set(key, value);
  }
}

5. Service Worker 缓存

实现离线缓存和网络请求拦截,适合 PWA 应用。

5.1 缓存接口数据
// sw.js
self.addEventListener('fetch', (event) => {
  if (event.request.url.includes('/api/')) {
    event.respondWith(
      caches.match(event.request).then((cachedResponse) => {
        return cachedResponse || fetch(event.request).then((response) => {
          const clone = response.clone();
          caches.open('api-cache-v1').then((cache) => {
            cache.put(event.request, clone);
          });
          return response;
        });
      })
    );
  }
});

6. 现代框架缓存方案

6.1 React Query
import { useQuery } from 'react-query';

function UserProfile() {
  const { data } = useQuery('userData', () =>
    fetch('/api/user').then(res => res.json()), {
      staleTime: 5 * 60 * 1000, // 5分钟缓存有效期
      cacheTime: 30 * 60 * 1000 // 30分钟保留时间
    });
  // ...
}
6.2 SWR (Stale-While-Revalidate)
import useSWR from 'swr';

function Profile() {
  const { data } = useSWR('/api/user', fetcher, {
    revalidateOnFocus: false, // 窗口聚焦时不刷新
    dedupingInterval: 60000   // 60秒内相同请求去重
  });
  // ...
}

7. 缓存策略关键问题处理

7.1 缓存失效
  • 时间戳失效:存储数据时记录时间戳,定期检查过期
  • 版本号控制:缓存键名包含版本号(如 user-v2
  • 主动清除:当数据变更时触发缓存更新
7.2 缓存一致性
  • 数据更新广播:通过 WebSocket 或 EventSource 通知前端更新缓存
  • 手动刷新机制:提供用户手动刷新按钮(如 pull-to-refresh
7.3 敏感数据处理
  • 避免缓存隐私数据(如 token、密码)
  • 使用 sessionStorage 替代 localStorage 存储会话数据

缓存方案选型建议

场景 推荐方案 容量 有效期
静态资源 HTTP 强缓存 无上限 长期
低频变动的接口数据 localStorage 5~10MB 自定义
大量结构化数据 IndexedDB 数百MB 长期
实时性要求高的数据 内存缓存 内存限制 页面会话
离线优先应用 Service Worker 50~250MB 自定义

最佳实践

  1. 分层缓存:结合 HTTP 缓存 + 内存缓存 + 持久化存储
  2. 缓存降级:优先从内存读取,其次本地存储,最后网络请求
  3. 监控指标:跟踪缓存命中率、存储使用量、数据新鲜度
  4. 安全清理:定时清理过期缓存,避免存储空间溢出

通过合理设计缓存机制,可显著提升前端性能,但在实际应用中需平衡以下关系:
新鲜度 vs 性能
存储空间 vs 用户体验
开发成本 vs 维护成本

你可能感兴趣的:(前端,缓存)