前端数据缓存的几种方式详细讲解

以下是前端数据缓存的完整解决方案,涵盖策略设计、技术实现和性能优化:


一、缓存策略分层设计

缓存策略
内存缓存
持久化缓存
Map/WeakMap
闭包变量
LocalStorage
SessionStorage
IndexedDB
Service Worker

二、核心场景实现方案

1. 高频请求数据缓存(内存缓存)
// 使用Map实现LRU缓存
class MemoryCache {
  constructor(maxSize = 100) {
    this.cache = new Map()
    this.maxSize = maxSize
  }

  get(key) {
    const item = this.cache.get(key)
    if (item) {
      // 更新访问顺序
      this.cache.delete(key)
      this.cache.set(key, item)
    }
    return item?.value
  }

  set(key, value, ttl = 60_000) {
    if (this.cache.size >= this.maxSize) {
      // 删除最久未使用的
      const oldestKey = this.cache.keys().next().value
      this.cache.delete(oldestKey)
    }

    this.cache.set(key, {
      value,
      expire: Date.now() + ttl
    })
  }

  clearExpired() {
    const now = Date.now()
    for (const [key, { expire }] of this.cache) {
      if (now > expire) this.cache.delete(key)
    }
  }
}

// 使用示例
const apiCache = new MemoryCache(50)
2. 持久化重要数据(LocalStorage + 版本控制)
const CACHE_VERSION = 'v1.3'

function getCache(key) {
  try {
    const data = localStorage.getItem(`${CACHE_VERSION}_${key}`)
    return data ? JSON.parse(data) : null
  } catch (error) {
    console.error('缓存读取失败', error)
    return null
  }
}

function setCache(key, value, ttl = 3600_000) {
  const data = {
    value,
    expire: Date.now() + ttl,
    timestamp: Date.now()
  }
  localStorage.setItem(
    `${CACHE_VERSION}_${key}`,
    JSON.stringify(data)
  )
}

// 定时清理过期缓存
setInterval(() => {
  Object.keys(localStorage).forEach(key => {
    if (key.startsWith(CACHE_VERSION)) {
      const data = JSON.parse(localStorage.getItem(key))
      if (data?.expire < Date.now()) {
        localStorage.removeItem(key)
      }
    }
  })
}, 60_000)
3. 接口请求缓存策略
const apiCache = new Map()

async function cachedFetch(url, options = {}) {
  const cacheKey = JSON.stringify({ url, options })
  
  // 命中缓存
  if (apiCache.has(cacheKey)) {
    const { expire, data } = apiCache.get(cacheKey)
    if (Date.now() < expire) return data.clone()
  }

  // 发起真实请求
  const response = await fetch(url, options)
  const cloneRes = response.clone()
  
  // 缓存新数据
  apiCache.set(cacheKey, {
    data: cloneRes,
    expire: Date.now() + (options.ttl || 300_000)
  })

  return response
}

三、高级缓存模式

1. 缓存分层策略
async function getData(key) {
  // 第一层:内存缓存
  let data = memoryCache.get(key)
  if (data) return data

  // 第二层:本地存储
  data = getLocalCache(key)
  if (data) {
    memoryCache.set(key, data)
    return data
  }

  // 第三层:网络请求
  data = await fetchData(key)
  memoryCache.set(key, data)
  setLocalCache(key, data)
  return data
}
2. 缓存更新策略
// Stale-While-Revalidate 模式
function swrFetch(url, ttl = 300_000) {
  const cached = getCache(url)
  
  // 立即返回过期数据,后台更新
  if (cached) {
    if (Date.now() < cached.expire) {
      return Promise.resolve(cached.value)
    } else {
      fetch(url)
        .then(updateCache)
        .catch(console.error)
      return cached.value
    }
  }

  // 无缓存则正常请求
  return fetch(url).then(updateCache)
}

四、性能优化方案

1. Web Worker 缓存处理
// 主线程
const worker = new Worker('cache-worker.js')

worker.postMessage({
  type: 'SET_CACHE',
  key: 'userData',
  value: userData
})

// Worker线程处理
self.onmessage = (e) => {
  if (e.data.type === 'SET_CACHE') {
    IndexedDB.set(e.data.key, e.data.value)
  }
}
2. 缓存压缩策略
function compressData(data) {
  const str = JSON.stringify(data)
  const compressed = LZString.compress(str)
  return compressed
}

function decompressData(compressed) {
  const str = LZString.decompress(compressed)
  return JSON.parse(str)
}

五、缓存监控与调试

1. 缓存命中率统计
const cacheStats = {
  total: 0,
  hits: 0,
  misses: 0
}

function trackCacheAccess(isHit) {
  cacheStats.total++
  isHit ? cacheStats.hits++ : cacheStats.misses++
  
  if (cacheStats.total % 100 === 0) {
    console.log(`缓存命中率: ${(cacheStats.hits/cacheStats.total*100).toFixed(1)}%`)
  }
}
2. Chrome DevTools 调试
// 暴露缓存接口到全局
window.__debugCache = {
  clear: () => {
    memoryCache.clear()
    localStorage.clear()
  },
  stats: () => cacheStats
}

六、最佳实践建议

  1. 缓存Key设计原则

    // 好的Key设计示例
    const getCacheKey = (apiPath, params) => {
      const sortedParams = Object.keys(params)
        .sort()
        .map(k => `${k}=${params[k]}`)
        .join('&')
      return `api_${apiPath}?${sortedParams}`
    }
    
  2. 敏感数据处理

    // 加密敏感缓存
    import CryptoJS from 'crypto-js'
    
    function secureSet(key, value) {
      const encrypted = CryptoJS.AES.encrypt(
        JSON.stringify(value),
        process.env.CACHE_SECRET
      ).toString()
      localStorage.setItem(key, encrypted)
    }
    
  3. 缓存容量控制

    // IndexedDB容量监测
    navigator.storage.estimate().then(estimate => {
      console.log(`已使用: ${estimate.usage/1024/1024}MB`)
      console.log(`限额: ${estimate.quota/1024/1024}MB`)
    })
    

七、不同场景推荐方案

场景推荐方案优势注意事项
高频更新数据内存缓存访问速度快需设置合理TTL
大型数据集IndexedDB支持结构化存储需处理版本迁移
离线优先Service Worker网络不可用仍可访问需处理缓存更新
敏感信息加密存储数据安全加解密性能损耗

通过合理使用这些缓存策略,可以实现:

  • 首屏加载速度提升 30%-70%
  • 接口请求量减少 40%+ 📉
  • 离线场景正常使用 📴
  • 流量消耗显著降低 🌐

建议结合业务需求选择缓存层级,并定期通过 window.performance.memory 监控内存使用情况,避免过度缓存导致内存泄漏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱分享的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值