前端缓存优化

前端缓存优化

缓存优化的核心是在**"速度"与"数据新鲜度"之间找到最佳平衡点。结合你之前的 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 条"。

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

相关推荐
怕浪猫1 小时前
FDE 如何正确解决现场项目工程性的问题
前端·后端·ai编程
西瓜太郎12341 小时前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
九皇叔叔1 小时前
【第二章】Redis基础入门:Redis是什么、为什么快以及核心特性详解
数据库·redis·缓存
GreenTea2 小时前
vLLM 与 SGLang KV Cache 底层实现机制深度调研报告
前端·后端·算法
几何心凉4 小时前
没有万能模型:我用 AiiOnly Token Plan,把多款大模型的长处拼进同一个项目
前端
kyriewen4 小时前
Claude Code 的额度今天缩水了17%——官方公告上写的是"永久提高25%"
前端·ai编程·claude
雪芽蓝域zzs5 小时前
vue解构平铺VS对象包裹
前端·javascript·vue.js
风骏时光牛马6 小时前
从零到实战,完整AI学习路线
前端
三十而立洋7 小时前
深入理解 Monorepo:子包安装依赖
前端·前端工程化
IT_陈寒7 小时前
Java Stream处理大集合,我的内存怎么就炸了
前端·人工智能·后端