智能小程序性能优化 02 - 首屏渲染优化与运行时优化

面板小程序开发相关产品技术讨论,包括面板小程序、智能小程序、React Native、Ray跨端框架、Panel SDK、微信小程序、小程序开发工具(IDE)及其他开发技术相关等话题


Post Reply
User avatar
Muzzzhi
Posts: 80

首屏渲染优化

小程序初次打开时的白屏阶段,是指小程序代码包下载完(也就是启动界面结束)之后,页面完成首屏渲染的这一阶段,也就是 FMP (首次有效绘制)。

FMP 没法用标准化的指标定义,但对于大部分小程序来说,页面首屏展示的内容都需要依赖服务端的接口数据,那么影响白屏加载时间的主要由这两个元素构成:

  • 网络资源加载时间
  • 渲染时间

启用本地缓存

小程序提供了读写本地缓存的接口 https://developer.tuya.com/cn/miniapp/a ... et-storage,数据存储在设备硬盘上,除此之外,缓存数据还可以作为兜底数据,避免出现接口请求失败时页面空窗。但并非所有场景都适合缓存策略,譬如对数据即时性要求非常高的场景(如抢购入口)来说,展示老数据可能会引发一些问题。

数据隔离:智能小程序目前会默认按照 uid和appId两个维度 对缓存空间进行隔离,业务可自行根据业务需求根据countryCode、家庭ID等维度进行再隔离,避免数据误展示。

miniapp-01.png

跳转时预拉取

为了尽快获取到服务端数据,比较常见的做法是在页面 onLoad 钩子被触发时发起网络请求,但其实这并不是最快的方式。从发起页面跳转,到下一个页面 onLoad 的过程中,小程序需要完成一些页面实例化的工作,耗时大概为 300ms左右。

实际上,我们可以在发起跳转前(如 navigateTo 调用前),提前请求下一个页面的主接口并存储在 globalData中,待下个页面加载完成后从 globalData 对象中读取数据即可。

这也是双线程模型所带来的优势之一,不同于多页面 web 应用在页面跳转/刷新时就销毁掉 window 对象。

分步渲染

保证重要信息优先展示
保证次要信息占位图

图片懒加载

小程序image在组件级别提供了图片lazy-load的能力。

骨架屏

业务数据请求回包之前使用骨架屏占位,提升体验。

运行时的优化

miniapp-02.png

从上述表格中可以看出,在小程序的双线程通信模式,数据量在一定程度上,会指数级上升。

所以运行时的优化最主要的原则就是减少通信频率,降低通信数据量

setData

业务开发阶段,开发者可以控制 setData 的频率,尽可能合并数据,减少调用次数。
开发者应该尽量减小调用 setData 的数据量,来提升通信效率。
只把渲染相关的数据放在data中。

去掉不必要的事件绑定

当用户事件(如 Click、Touch 事件等)被触发时,视图层会把事件信息反馈给逻辑层,这也是一个线程间通信的过程。但,如果没有在逻辑层中绑定事件的回调函数,通信将不会被触发。

所以,尽量减少不必要的事件绑定,尤其是像 onPageScroll 这种会被频繁触发的用户事件,会使通信过程频繁发生。

注意:Touch事件,使用前要思考是否必须要绑定该事件到逻辑层触发,是否可以在SJS中处理该事件。

去掉不必要的节点属性

组件节点支持附加 自定义数据 dataset,当用户事件被触发时,视图层会把事件 target 和 dataset 数据传输给逻辑层。那么,当自定义数据量越大,事件通信的耗时就会越长,所以应该避免在自定义数据中设置太多数据。

Code: Select all

<view class="title">弹出位置</view>
<view class="box">
  <button class="btn" bindtap="popup" data-position="right">右侧弹出</button>
  <button class="btn" bindtap="popup" data-position="top">顶部弹出</button>
  <button class="btn" bindtap="popup" data-position="bottom">底部弹出</button>
  <button class="btn" bindtap="popup" data-position="center">中央弹出</button>
</view>

Code: Select all

changeOverlayStyle(e) {
    let overlayStyle = ''
    const type = e.currentTarget.dataset.type
    switch (type) {
      case 'black':
        overlayStyle = 'background-color: rgba(0, 0, 0, 0.7)'
        break
      case 'white':
        overlayStyle = 'background-color: rgba(255, 255, 255, 0.7)'
        break
      case 'blur':
        overlayStyle = 'background-color: rgba(0, 0, 0, 0.7); filter: blur(4px);'
    }
    this.setData({ overlayStyle, show: true })
  },

SJS使用

SJS 将一些视图层需要计算的能力放在SJS中操作。

SJS运行在视图层
SJS可以处理视图层绑定的事件且可以获取当前所在实例的部分能力。https://developer.tuya.com/cn/miniapp/f ... /event/sjs
SJS并不是完全的JavaScript,仅具有部分Safe的能力。
处理事件、工具函数,无需通信。

Render Script

渲染脚本,可用于处理高频的绘图需求,可以提高视图的动画渲染性能,主要应用场景 canvas 图表渲染,webGL 图形渲染等。

关于RJS的问题可以查看这里哦: https://tuyaos.com/viewtopic.php?p=884&hilit=RJS#p884

销毁持久化内存

根据双线程模型,小程序每一个页面都会独立一个 webview 线程,但逻辑层是单线程的,也就是所有的 webview 线程共享一个 JS 线程。以至于当页面切换到后台态时,仍然有可能抢占到逻辑层的资源,譬如没有销毁的 setInterval、setTimeout 定时器:

即使如小程序的 <swiper> 组件,在页面进入后台态时依然是会持续轮播的。
正确的做法是,在页面 onHide 的时候手动把定时器清理掉,有必要时再在 onShow 阶段恢复定时器。

坦白讲,区区一个定时器回调函数的执行,对于系统的影响应该是微不足道的,但不容忽视的是回调函数里的代码逻辑,譬如在定时器回调里持续 setData 大量数据,这就非常难受了。

去掉调试工具VConsole

VConsole 是挂载到视图层的调试工具,逻辑层的日志会通过通道发到视图层,日志打印频繁可能会阻塞通道,遇到性能要求较高的页面调试,去掉vconsole调试工具,减少通道占用。

性能指标

首屏时间不超过 5 秒;
渲染时间不超过 500ms;
每秒调用 setData 的次数不超过 20 次;
setData 的数据在 JSON.stringify 后不超过 256kb;
页面 TYML 节点少于 1000 个,节点树深度少于 30 层,子节点数不大于 60 个;
所有网络请求都在 1 秒内返回结果;

:geek: :ugeek: :mrgreen: :roll: :lol: :idea: :arrow: LGTM


Tags:
User avatar
Muzzzhi
Posts: 80

Re: 智能小程序性能优化 02 - 首屏渲染优化与运行时优化

快速定位第一篇 数据分析与启动阶段优化 https://tuyaos.com/viewtopic.php?t=249

:geek: :ugeek: :mrgreen: :roll: :lol: :idea: :arrow: LGTM

User avatar
TheThingX
Posts: 65
Location: TheThingX
Contact:

Re: 智能小程序性能优化 02 - 首屏渲染优化与运行时优化

:twisted: :twisted: :twisted: :twisted:

[][TheThingX.com]
Post Reply