阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 缓存策略规范

缓存策略规范

作者:陈川 阅读数:36313人阅读 分类: 前端综合

缓存策略是前端性能优化的重要手段,合理的工程化规范能确保缓存机制高效可控。从本地存储到HTTP缓存,不同场景需要针对性设计,同时避免常见陷阱。

本地存储规范

本地存储包括localStorage、sessionStorage和IndexedDB,适用于需要持久化或大量结构化数据的场景。工程实践中需建立明确的存储命名规范:

// 项目前缀+模块名+业务键名 三级命名规范
const STORAGE_KEY = 'PROJ_USER_TOKEN'; 
const HISTORY_KEY = 'PROJ_SEARCH_HISTORY';

// 封装统一操作接口
export const storage = {
  set(key, value) {
    try {
      localStorage.setItem(key, JSON.stringify(value));
    } catch (e) {
      console.error('LocalStorage写入失败', e);
      // 自动降级处理
      sessionStorage.setItem(key, JSON.stringify(value));
    }
  },
  get(key) {
    const data = localStorage.getItem(key) || sessionStorage.getItem(key);
    try {
      return data ? JSON.parse(data) : null;
    } catch {
      return data; // 兼容非JSON数据
    }
  }
};

容量控制策略

  • 单个域名下localStorage限制通常为5MB
  • 超过阈值时采用LRU算法自动清理
  • 敏感数据需设置自动过期时间
// LRU缓存实现示例
class LRUCache {
  constructor(maxSize) {
    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);
  }
}

HTTP缓存策略设计

HTTP缓存分为强缓存和协商缓存,需根据资源类型配置不同策略:

强缓存配置示例(Nginx)

location ~* \.(js|css|png)$ {
  expires 365d;
  add_header Cache-Control "public, max-age=31536000, immutable";
}

动态资源协商缓存配置

location /api {
  add_header Cache-Control "no-cache";
  etag on;
}

缓存更新策略对比

策略类型 实现方式 适用场景 示例
文件名哈希 构建工具生成hash文件名 静态资源 app.3a7b8c.js
查询参数版本 URL追加?v=1.0.0 第三方库 lib.js?v=2.1.4
路径版本控制 版本化目录结构 多环境部署 /v2/assets/logo.png
后台推送更新 Service Worker控制 PWA应用 self.skipWaiting()

Service Worker缓存策略

Service Worker提供精细的缓存控制能力,常用策略包括:

缓存优先网络回退方案

// sw.js
const CACHE_NAME = 'v1';

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((cached) => {
      return cached || fetch(event.request).then((response) => {
        // 动态缓存非GET请求和opaque响应
        if (event.request.method !== 'GET' || response.status === 0) {
          return response;
        }
        
        const responseToCache = response.clone();
        caches.open(CACHE_NAME).then((cache) => {
          cache.put(event.request, responseToCache);
        });
        
        return response;
      }).catch(() => {
        // 网络失败时返回备用内容
        return new Response('离线备用内容');
      });
    })
  );
});

预缓存关键资源

// 构建时生成的预缓存列表
const PRE_CACHE_LIST = [
  '/css/main.css',
  '/js/app.js',
  '/offline.html'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(PRE_CACHE_LIST))
      .then(() => self.skipWaiting())
  );
});

缓存更新与失效机制

有效的缓存失效策略是工程化重点:

版本号控制方案

// webpack配置示例
output: {
  filename: '[name].[contenthash:8].js',
  chunkFilename: '[name].[contenthash:8].chunk.js'
}

API请求缓存控制

// 封装带缓存的fetch
const apiCache = new Map();

async function cachedFetch(url, options = {}) {
  const cacheKey = `${url}_${JSON.stringify(options)}`;
  
  // 检查内存缓存
  if (apiCache.has(cacheKey)) {
    const { data, timestamp } = apiCache.get(cacheKey);
    if (Date.now() - timestamp < 300000) { // 5分钟有效期
      return data;
    }
  }
  
  // 实际请求
  try {
    const res = await fetch(url, options);
    const data = await res.json();
    
    // 更新缓存
    apiCache.set(cacheKey, {
      data,
      timestamp: Date.now()
    });
    
    return data;
  } catch (error) {
    // 失败时返回缓存数据(如果有)
    if (apiCache.has(cacheKey)) {
      return apiCache.get(cacheKey).data;
    }
    throw error;
  }
}

特殊场景处理

表单提交防重复缓存

<!-- 使用autocomplete控制 -->
<form autocomplete="off">
  <input type="text" name="key" autocomplete="new-password">
</form>

视频分段缓存策略

// MediaSource扩展缓冲
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', () => {
  const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"');
  
  fetch('/video/segment1.mp4').then(response => {
    return response.arrayBuffer();
  }).then(data => {
    sourceBuffer.appendBuffer(data);
  });
});

监控与异常处理

建立缓存健康度监控体系:

// 缓存命中率统计
window.addEventListener('load', () => {
  const timing = performance.getEntriesByType('navigation')[0];
  const cacheRatio = (timing.transferSize - timing.encodedBodySize) / timing.transferSize;
  analytics.send('cache_hit_ratio', cacheRatio);
});

// 缓存异常监控
window.addEventListener('error', (e) => {
  if (e.message.includes('QuotaExceededError')) {
    metrics.increment('storage.quota_exceeded');
  }
});

多环境差异化配置

不同环境应采用不同缓存策略:

// 环境检测与策略切换
const getCacheStrategy = () => {
  if (process.env.NODE_ENV === 'development') {
    return {
      apiCacheTTL: 0,
      staticAssets: 'no-store'
    };
  }
  
  if (location.host.includes('staging')) {
    return {
      apiCacheTTL: 300000,
      staticAssets: 'max-age=300'
    };
  }
  
  return {
    apiCacheTTL: 3600000,
    staticAssets: 'max-age=31536000'
  };
};

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌