前端缓存优化

前端缓存优化

缓存优化的核心是在**"速度"与"数据新鲜度"之间找到最佳平衡点。结合你之前的 uni-app/小程序背景,缓存优化不仅是"存起来",更要考虑 存储空间限制(微信小程序仅10MB)和异步读取的耗时**。

我把缓存优化分为四个层级来拆解,按投入产出比排序如下:

🗂️ 第一层:静态资源缓存(网络层)

这是性价比最高的优化,让图片、JS、CSS 等文件**"强缓存"**在用户本地,避免重复下载。

  • 核心机制 :服务端响应头设置 Cache-Control(强制缓存)和 ETag(协商缓存)。
  • 最佳实践 :
    • 带 Hash 的永久缓存 :构建工具(Vite/Webpack)给文件名加上 hash 值(如 main.a3f2e1.js)。文件内容不变,Hash 不变;内容一变,URL 就变。此时可设置 Cache-Control: max-age=31536000(一年),用户永远只下载一次,除非版本更新。
    • CDN 加速 :将静态资源上传至 CDN,利用 CDN 的边缘节点就近返回数据。注意在 manifest.json 中配置 CDN 地址作为资源基础路径。

📦 第二层:接口数据缓存(业务层)

这是体验改善最明显的一层,用于缓存列表、详情、配置等非实时数据。

  • 内存缓存(最快) :在 Vuex/Pinia/Zustand 的 Store 中存一份。页面返回时,0ms 读取,瞬间展示。注意:页面刷新或小程序冷启动会丢失。
  • 本地磁盘缓存(持久化) :利用 uni.setStorage / wx.setStorage(小程序异步 API)。
    • 策略 1:先缓存后网络(Stale-While-Revalidate):打开页面时,先立即读取本地缓存展示旧数据,同时发起网络请求。请求成功后,用新数据更新页面和缓存。用户感知不到白屏。

    • 策略 2:手动封装请求缓存(防重复请求) :在 uni.request 外层封装一层。如果 500ms 内发起两次相同的 API 请求(如首页并发请求),只发一次网络请求,第二个直接复用第一个的 Promise。

    • 代码示例(请求缓存池) :

      javascript 复制代码
      // 简易请求去重器
      const pendingMap = new Map();
      function requestWithCache(url, params) {
        const key = url + JSON.stringify(params);
        // 如果正在请求中,直接返回之前的 Promise
        if (pendingMap.has(key)) {
          return pendingMap.get(key);
        }
        const promise = uni.request({ url, data: params }).then(res => {
          pendingMap.delete(key); // 请求完毕清除
          // 同时存入 Storage(异步)
          uni.setStorage({ key: `cache_${key}`, data: res.data });
          return res;
        });
        pendingMap.set(key, promise);
        return promise;
      }

🖼️ 第三层:图片与渲染缓存(视觉层)

  • 小程序图片缓存 :<image> 组件默认有缓存,但不总是可控。如果使用 uni-app,建议在 image 上加上 webp 属性(体积更小),并开启 lazy-load。
  • 骨架屏与占位缓存 :将加载中的骨架屏代码嵌入到 WXML/Vue 模板中。首次加载展示骨架,数据回来后替换。配合 Storage 记录"是否首次访问",如果是老用户,甚至可以直接先渲染缓存数据,再异步请求刷新。

⚙️ 第四层:小程序独有的缓存机制(代码包与编译)

  • 更新机制 :微信小程序冷启动时会异步检查代码包是否有新版本。但下载新包是静默的,下一次冷启动 才会使用新包。
    • 主动更新策略 :如果发现版本更新频繁,可以在 App.onLaunch 中调用 wx.getUpdateManager,强制用户重启应用更新,避免旧缓存代码与新接口不匹配报错。
  • Storage 容量警戒 :小程序单 key 限制 1MB,整体上限 10MB。需要做 LRU(最近最少使用)策略 :存数据时检查总大小,如果接近 10MB,优先删除最旧的、非核心的缓存数据,防止 setStorage 写入失败。

🧠 缓存的"灵魂三问"(失效策略)

缓存最怕"脏数据"(显示旧数据)。必须配套清晰的失效机制:

  1. 按时间失效(TTL) :存数据时带上时间戳 { data: {...}, expire: Date.now() + 60000 }。读取时判断是否过期,过期就发起请求。
  2. 按事件失效(主动清除) :用户退出登录、支付成功、发布评论后,主动调用 uni.removeStorageSync('home_list') 清除相关缓存,而不是等过期。
  3. 按版本失效 :当 App 发版(manifest.json 中的 versionName 变更)时,在启动时清空所有旧缓存(uni.clearStorage),避免新旧数据结构不兼容。

💡 针对你当前场景的特别建议

如果你正在做商品详情页或信息流列表:

  • 详情页:非常推荐"先缓存后网络"策略。因为商品名、图片、价格短时间内不会大变,秒开体验远超转菊花。
  • 列表页(带分页) :不要缓存整个列表滚动位置,容易导致内存溢出。只需缓存第一页的数据。用户返回时,先展示第一页旧数据,再请求最新数据,并提示"已更新 N 条"。

你可以先上手封装那个**"请求去重器"**,这几乎是零成本换来并发接口速度翻倍。如果针对某个特定场景(比如表单回填或搜索建议)的缓存拿不准,可以具体说说,我再给你针对性代码。

相关推荐
可乐鸡翅yeah_12 小时前
AES‑128 加密 M3U8,IV 初始化向量新手容易踩坑
前端·网络·数据库·ffmpeg·音视频·m3u8在线
MetWeave12 小时前
机场天气的"广播系统":三种报文一次讲明白
前端
hweiyu0012 小时前
Redis命令:HPEXPIREAT
redis·缓存
xieter12 小时前
【技术精选】深入浅出现代前端渲染与性能优化实践指南 (2026-10-04)
前端·javascript
code2cat13 小时前
【随笔】MCP缓存期限与共享范围:让Agent复用资料时记住边界
java·后端·缓存·ai agent·mcp
计算机魔术师13 小时前
Anthropic 密会宗教领袖谈 Claude 意识,OpenAI 为什么急眼
前端
xieter13 小时前
【硬核实战】TypeScript Compiler API: Preserving Child Node Narrowing in Reusable Type Guards 🔧 (2026-10-03)
前端·javascript
xieter13 小时前
【硬核实战】React 19 useFormStatus Returning False? I Built a SubmitButton That Fixes It (2026-10-03)
前端·javascript
Data analyse45614 小时前
Cookie过期引发UV上涨的复核方法
服务器·前端·数据分析·uv
Highcharts.js14 小时前
图表开发实战总结| 7 条“黄金法则”与“性能铁律”
前端·javascript·vue.js·编辑器·时序数据库·highcharts