前端缓存优化

前端缓存优化

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

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

相关推荐
老王以为39 分钟前
走进 AI Agent 第二篇:决定 AI Agent 能力上限的关键技术
前端·人工智能·机器学习
何以解忧,唯有..1 小时前
Python 异常处理完全指南:从基础到高级实践
开发语言·前端·python
Buke..1 小时前
【小程序逆向】某游快爆 AI 逆向 sign参数:AI 辅助分析与 MCP 工具链实战
前端·人工智能·爬虫·python·小程序·notepad++
ly76892 小时前
CSS 从入门到进阶:系统掌握现代网页样式与布局
前端·css
SWAGGY..3 小时前
【C++初阶】:(15)模板进阶--从非类型参数到模板特化与分离编译
java·服务器·前端
YHHLAI3 小时前
从「跑分」到「干活」:Benchmark 与 GPT 5.6 的两种叙事
大数据·前端·人工智能·react.js·前端框架
BigTopOne3 小时前
ArLiveLite 用到的 C++/JNI 技术点
前端
BigTopOne3 小时前
ArLiveLite 技术架构-Lite
前端