前端缓存优化

前端缓存优化

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

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

相关推荐
用户1880687493522 分钟前
戴着 Rokid 接成语:用 AIUI 做一局有提示、有复盘的“接着说”
前端
Sakura_j_h_11 分钟前
Three.js 单文件离线机械臂工作台:爆炸图、透明外壳与剖面
前端·机械臂·webgl·three.js·1024程序员节·esbuild
计算机魔术师2 小时前
管谷歌的不是Pichai一个人,是一整层AI智能体
前端
米米商聊2 小时前
图标能点,按钮就可用了吗?键盘、名称与收藏状态
前端·javascript
Younglina2 小时前
三个晚上,我和 WorkBuddy 做了个生图网站
前端·后端·ai编程
xy34532 小时前
Axure 9.0 内联框架加载方式
前端·ui·html·axure·原型·产品设计
陈随易4 小时前
副业搞钱点子之收入查看器
前端·后端
Profile排查笔记4 小时前
浏览器指纹逆向怎么分析:从网络请求追踪到 JavaScript 采集链
前端·人工智能·后端·自动化
小南家的青蛙4 小时前
Redis的资料
redis·缓存·1024程序员节
hudie7654 小时前
LikeShop 二开最常改的 5 个文件(附改前改后对比)
前端·uni-app·php·个人开发