小程序运行时性能优化收藏我的收藏
收藏
我的收藏小程序的运行时性能直接决定了用户在使用小程序功能时的体验。如果运行时性能出现问题,很容易出现页面滚动卡顿、响应延迟等问题,影响用户的使用。如果内存占用过高,还会出现黑屏、闪退等问题。
合理使用 setData
setData 的过程,大致可以分成几个阶段:
- 1.逻辑层虚拟 DOM 树的遍历和更新,触发组件生命周期和 observer 等
- 2.将 data 从逻辑层发送到视图层
- 3.更新视图层虚拟 DOM 树、真实 DOM 元素并触发页面渲染
由于小程序的逻辑层和视图层是两个独立的运行环境,不能直接进行数据共享,需要进行数据的序列化、跨线程/进程的数据传输、数据的反序列化,因此数据传输过程是异步的、非实时的。数据传输的耗时与数据量的大小正相关,如果对线程处于繁忙状态,数据会在消息队列中等待,导致处理队列阻塞,界面渲染不及时而导致卡顿,应避免无用的频繁调用。具体优化手段有:
- •合并发送数据。频繁的数据更新会导致页面不断重新渲染,导致渲染线程繁忙,进而阻塞交互事件的响应
- •不发送与页面渲染无关的数据。setData 是作为页面渲染数据更新的来源,与页面渲染无关的数据可以存储到本地或挂载到页面或全局对象
- •处于后台不调用。后台态页面的渲染用户是无法感受的,另外后台态页面去 setData 也会抢占前台页面的执行,造成不必要的性能开销
- •不在高频事件中调用。如 scroll 事件中
- •动画减少使用 setData。优先使用 CSS 渐变、CSS 动画
控制 TTML 节点数量和层级
节点树太大会增加内存的使用,样式重排时间也会更长,影响体验。建议一个页面 TTML 节点数量应少于 1000 个,节点树深度少于 30 层,子节点数不大于 60 个。
合理使用自定义组件
- •合理拆分自定义组件。Page 中的 setData 会触发渲染层以页面级别进行 diff 操作,如果页面比较复杂且没有使用自定义组件,那么 diff 的成本会很高,导致体验比较差(更新卡顿、不粘手等感受)。如果页面转换为若干个组件,组件中 setData, 只会触发渲染层对应组件的 diff 操作,diff 成本会降低很多,使用体验也会更优。但自定义组件的使用会引入前置的注册和自定义组件生命周期执行逻辑,因此建议将业务逻辑比较独立或变更频率较大的部分进行拆分,避免盲目拆分
- •只注册当前使用的组件。为了保证自定义数据在不同的页面实例中也是不同的实例,小程序框架会在页面创建时对这部分数据(函数类型字段除外)做一次深拷贝,如果自定义数据过多或过于复杂,可能带来很大的开销。因 此建议在
usingComponents
中应只注册当前页面有使用到的自定义组件- •按需使用同步修改 data 的能力。在
app.json
中增加配置component2: true
后,支持在 created
生命周期中修改自定义组件初始数据,自定义组件将在created
生命周期执行完成后开始渲染。- ◦开启后有以下优化点:避免由于 data 变化导致页面渲染内容闪动或频繁变动问题
- ◦开启后的限制:避免在 created 中如果有较多同步逻辑,同步过多会影响小程序性能
合理监听事件
- •合理监听和处理 scroll 事件。scroll 事件中高频执行耗时操作,会明显降低 FPS
- •去掉不必要的事件绑定。过多的事件绑定(ttml 中的 bind 和 catch),也会增大通信的数据量和次数。渲染层会接受用户事件,如点击事件、触摸事件等。用户事件的通信过程:当一个用户事件被触发且有相关的事件监听器需要被触发时,渲染层会将信息反馈给逻辑层。如果一个事件没有绑定事件回调函数,则这个事件不会被反馈给逻辑层
内存优化
- •及时解绑事件监听。事件监听结束后,应及时解绑监听器
- •及时清理定时器。开发者在开发如「秒杀倒计时」等功能时,可能会使用
setInterval
设置定时器,页面或组件销毁前,需要调用clearInterval
方法取消定时器导航栏适配
清晰的导航能告诉用户当前在哪里、能到哪里去、并能原路返回。除了默认的导航栏外,开发者也可以根据需求申请权限,设计自定义导航栏适配小程序风格。
- •适当开启自定义导航栏。避免在
app.json
中全局开启动态导航栏,仅在需要的页面中配置,降低适配成本- •关键信息避开状态栏和胶囊按钮。如果开启自定义导航栏,需要通过 tt.getCustomButtonBoundingClientRect 获取自定义导航栏下不可改变的元素位置信息以适配导航栏
适配分屏
正常情况下页面默认是撑满整个视口的,但在直播小程序卡片、POI 详情页商品入口会出现七分屏场景。
- •通过 onResize 监听显示区域变化。小程序支持组件和页面的生命周期函数
onResize
用于在显示区域的尺寸发生变化的时候返回当前页面的信息。其中组件需要作为页面配置到app.json
中触发事件- •不使用 JS 设置 ScrollView 高度。scroll-view 中分屏变为全屏时需要重新设置 scroll-view 高度,可能会出现空白区域问题,建议使用 CSS(vh)完成自适应布局