小程序性能优化:从启动到 setData

admin 微信QQ技巧 2026-10-17 2 0

你打开小程序,首页要转两秒才出来;往下滑到第 200 条数据时手指一顿一顿;点一个按钮,整页都重绘了。你以为是手机差,换成旗舰机也一样。小程序性能问题几乎都不是玄学,成因很具体:包太大导致下载解压慢、setData 传了不该传的东西、长列表一次性渲染全部节点。每一条都有明确做法可以量化改善。

一、先分清启动性能与运行性能

这是两类不同的优化对象。启动性能关心「从点击图标到首屏可用」,决定性因素是包体积和初始化逻辑量;运行性能关心「页面卡不卡」,取决于渲染数据量、频次和长列表策略。

优化前先量一下。开发者工具里有体验评分和性能面板,能看到启动耗时、首次渲染时间、setData 的调用次数与数据大小。没有数据的优化都是猜,给自己定两个指标:首屏可见时间、滑动掉帧情况,每次改动后复测。

二、主包体积:最有效的杠杆

主包体积有硬性上限,直接影响冷启动的下载与解压时间。超了就必须拆分包,即使没超,能压小也值得。

用分包承载非首屏内容

分包后主包只放首页与公共依赖,其余页面按业务拆到子包,用户进入时才下载。拆分标准很简单:首屏路径上不需要的页面全部移出去。子包之间不能互相引用,公共模块要么提到主包,要么复制一份;确实有跨包共享代码时,可以配合分包异步化,做成需要时才加载的形式。别忘了预下载——首页渲染完成后主动触发子包预下载,用户点进详情时子包已在本地。

体积控制的具体手段

  • 图片全部挪到 CDN,包里不留大图,首屏之外的用远程地址懒加载。
  • 把多页共用的工具函数、配置、组件抽成公共模块,避免每个子包各打一份。
  • 删掉没用的代码。包里往往躺着废弃页面、调试假数据、整个引进来只用了一个函数的库。
  • 按需注入:只注入当前页面需要的代码与自定义组件,别把所有页面组件都塞进启动流程。

初始渲染缓存

它让页面在逻辑层还没准备好时先展示一份上次的快照,用户看到内容的时间明显提前,适合不依赖实时数据的静态页面。注意数据可能过期,展示前留一个短暂的加载态。

三、setData 的三个原则

setData 是这里最贵的操作,它要把数据序列化后从逻辑层传到视图层,数据越大、次数越多、层级越深开销越高。三个原则能解决大部分卡顿。

量少

只传视图层真正要用的数据。典型错误是把接口原始报文整包 setData,其中大半字段根本不显示。

频次低

合并短时间内的多次更新。滚动监听里每帧都 setData 是最常见的灾难来源,改成节流或只在临界值变化时更新。表单输入同理。

路径精准

用数据路径直接更新单个字段,而不是整个对象重新赋值。

// 差:整个列表重传,一千条就是一千条的开销
this.setData({ list: newList });

// 好:只更新第 3 条的 status
this.setData({ 'list[3].status': 1 });

// 好:只更新对象的一个字段
this.setData({ 'form.title': value });

还有一个隐藏成本:不要把函数、节点、不可序列化的对象放进 data。纯数据留在 data,逻辑留在页面方法里。

四、长列表怎么渲染

一次性渲染上千条节点,怎么优化 setData 都救不回来。三条路按场景选。

虚拟列表

只渲染视口内可见的若干条,滚动时动态替换数据,节点数量恒定,滚动始终流畅。代价是实现复杂,要处理行高计算、滚动位置同步、快速滑动的白屏。

分页加载

一次只渲染几十条,滚到底部再加一批。实现简单,但一直往下拉时节点总数还是会膨胀,通常配合「超出一定条数后丢弃远端数据」来限制。

骨架屏与占位

数据没到时先渲染结构一致的占位块,给等待一个视觉交代。它不减少真实耗时,但改善主观感受,骨架要贴近真实布局,尺寸跳变会让人觉得更慢。

方案适用场景注意点
虚拟列表数据量大、滚动频繁、行高可预测实现复杂,注意快速滑动白屏
分页加载数据中等、用户很少滑到很深限制总节点数,及时释放旧数据
骨架屏所有需要等待网络的首屏尺寸贴近真实内容,避免跳动

五、图片是最容易漏掉的成本

一个页面的内存与渲染压力,很大比例来自图片。四个动作立刻见效。

  1. 请求尺寸合适的图:服务端或 CDN 按展示尺寸裁切,别把 2000px 缩到 200px 显示。
  2. 换格式:支持的话优先用压缩率更好的新格式,同时保留回退。
  3. 懒加载:视口之外的图延迟请求,滚动到附近再加载。
  4. 设固定尺寸:给容器明确宽高,避免图片加载后把页面顶得跳动。

六、网络请求与缓存

首屏常被串行请求拖慢:先拿用户信息,再用它拿列表,再拿列表拿详情。把能并行的并行,把能提前的提前,首屏用一次批量接口返回必要字段。

两条路:网络层缓存头,和本地存储。把不常变的配置、字典数据存本地并带过期时间。

const cached = wx.getStorageSync('config');
if (cached && Date.now() - cached.time < 3600e3) {
  this.applyConfig(cached.data);
}

request('/api/config').then(res => {
  wx.setStorageSync('config', { data: res, time: Date.now() });
  this.applyConfig(res);
});

控制关键的几个并行,其余延后。

七、体验评分里真正影响用户的几项

工具会给很多条建议,有的对真实感受影响巨大,有的只是锦上添花。按优先级排:

  • 首屏可见时间:最核心。点图标后多久看到内容,直接决定用户会不会退出。
  • 交互响应:按钮点下去有没有即时反馈,没有反馈的 500 毫秒在感知上像卡死。
  • 滑动流畅度:长列表卡顿是最大的差评来源,优先处理。
  • 请求失败要有提示,避免布局抖动:空白页与内容跳动都会让人误操作。

八、优化项与收益、成本对照

优化项收益实施成本
图片上 CDN 并裁切尺寸高,包体积与内存双降低
拆分分包高,主包明显变小中,需调整目录与依赖
分包预下载中高,消除二次跳转等待低
按需注入中,启动流程变轻低
初始渲染缓存高,首屏感知大幅提前中,需处理数据时效
setData 精简与合并高,直接改善卡顿中,需逐页排查
虚拟列表高,长列表体验质变高
请求并行与批量接口中高,首屏时间缩短中,需后端配合
本地缓存字典数据中,重复进页面秒开低

先把「大图、大包、大 setData」砍掉,多数项目的体验就从难用变成可用了。虚拟列表这类重投入方案,等前三条做完再看数据决定。