微信小程序怎么渲染性能调优

作者:创搜网络科技 2019-07-31 14:48:52

网页性能优化是前端开发的热门话题。 WeChat applet采用双线程架构设计,因此性能优化方法与传统的H5应用程序不同。今天,我主要介绍微信applet页面的双线程架构对页面渲染的一些影响,以及一些渲染性能调优策略。为了便于描述,微信小程序将被称为小程序。
微信小程序怎么渲染性能调优

01小程序双线程架构

与传统浏览器网页的最大区别在于applet基于双线程模型。在这个架构中,applet的渲染层使用WebView作为渲染向量,而逻辑层则从单独的JsCore线程运行JS脚本。双方没有直接数据共享的通道,因此渲染层和逻辑层之间的通信由Native JSBrigde中继。

applet更新视图数据的通信过程

每当需要更新applet视图数据时,逻辑层调用applet主机环境提供的setData方法将数据从逻辑层传递到视图层,并在一系列渲染步骤之后完成UI视图更新。完整的沟通过程如下:

applet逻辑层调用主机环境的setData方法。

逻辑层执行JSON.stringify以将要传输的数据转换为字符串并将其拼接到特定的JS脚本中,并通过evaluateJavascript执行脚本以将数据传输到呈现层。

收到渲染层后,WebView JS线程编译脚本,获取要更新的数据,并进入渲染队列以等待WebView线程在呈现页面时空闲。

当WebView线程开始渲染时,要更新的数据将合并到视图层保留的原始数据数据中,新数据将应用于WXML片段以获取新的虚拟节点树。在将新虚拟节点树与当前节点树的diff进行比较之后,将差异更新为UI视图。同时,将旧节点树替换为旧节点树以进行下一次重新渲染。

02呈现性能问题的一些原因

在上述通信过程中,一些不适当的操作可能会影响页面呈现的性能。

setData传递了大量新数据

数据传输将经历跨线程传输和脚本编译的过程。当数据量太大时,会增加脚本编译的执行时间并占用WebView JS线程。

频繁执行setData将使WebView JS线程忙于脚本编译,节点树比较计算和页面呈现。结果是:

页面呈现结果有一定的延迟。

当用户触发页面事件时,WebView JS线程忙,并且用户事件未及时传输到逻辑层,导致反馈延迟。

页面节点太多

当最初渲染页面时,渲染树的构造,计算节点的几何形状以及将节点绘制到屏幕所花费的时间都与页面节点的数量正相关。页面节点越多,渲染时间越长。

每次执行setData更新视图时,WebView JS线程都会遍历节点树以计算新节点和新节点之间的差异。当页面节点数量较大时,计算时间成本较大,减少节点树节点数量可以有效减少重新渲染的时间开销。
微信小程序怎么渲染性能调优

03渲染性能优化

基于渲染性能问题的原因,我们可以开发一些优化策略来避免性能问题。

setData优化

setData是与视图层作为逻辑层进行通信的媒介,并且是最有可能导致渲染性能瓶颈的API。我们应该在使用setData时遵循一些规则,以尽可能避免性能问题:

减少setData数据传输量

仅传输视图层使用的数据,其他JS环境使用的数据存储在数据对象外部。

合理使用本地更新。 setData是支持使用数据路径来更新对象的本地字段,我们可能会遇到这样的场景:列表列表是从后台获取的数据,并显示在页面上,当列表列表的第一个数据时src当需要更新字段时,通常我们将从后台获取新的列表列表并执行setData以更新整个列表列表。

//在后台获取列表数据

Const list=requestSync();

//更新整个列表

this.setData({list});

实际上,只有当需要更新单个字段时,我们才能编写以避免整个列表更新:

//在后台获取列表数据

Const list=requestSync();

//部分更新列表

this.setData({

'list [0] .src': list [0] .src

});

降低setData执行频率

组合并执行多个setData调用,而不会影响业务流程,从而降低了线程之间的通信频率。当您需要在频繁触发的用户事件(例如PageScroll,Resize事件)中调用setData时,您可以使用debounce和throttle函数来减少setData执行的次数。

功能去抖:该功能在触发n秒后执行一次。如果在n秒内重复触发功能,则重新计算时间。

节流:每单位时间只触发一个功能。如果在同一单位时间内触发多个功能,则只有一个功能生效。

除了让开发人员有意识地遵循规则来减少setData数据传输量和执行频率之外,我们还可以设计一个diff算法,重新打包setData,这样要更新的数据和setData之前的原始数据数据是执行Diff比较,计算数据差异补丁对象,判断补丁对象是否为空,如果为空则跳过执行更新,否则对补丁对象执行setData操作,从而减少数据传输量,降低执行setData。

充分利用自定义组件

Expleter框架支持applet自定义组件的实现,该框架由applet正式设计。框架实现的自定义组件的组件模型类似于Web组件标准的Shadow DOM:

页面引用自定义组件后,初始化页面时,Exparser将根据自定义组件的注册信息实例化组件,然后根据数据数据和组件WXML构建组件。一个单独的影子树并附加到页面组成树。创建的Shadow Tree有自己独立的逻辑空间,数据,样式环境和setData调用:

基于自定义组件的Shadow DOM模型设计,我们可以在页面中封装一些功能模块(例如倒计时,进度条等),这些模块需要将setData更新高频执行到页面中嵌入的自定义组件中。

当需要更新这些自定义组件视图时,将执行组件自己的setData。新旧节点树的比较计算和渲染树的更新仅限于组件中有限数量的节点,这有效地减少了渲染时间开销。

当然,使用自定义组件越多越好。如果向页面添加自定义组件,Exparser需要更多地管理一个组件实例。内存消耗会更大。当内存使用量上升到一定程度时,可能会导致iOS部分WKWebView回收,Android体验将变得更加愚蠢。因此,有必要合理使用自定义组件,页面设计也应注意不要滥用标签。

04摘要

小程序双线程架构确定数据通信优化是性能优化中的重要一点。上述优化建议仅是优化渲染性能的一部分。为了使您的页面体验更加柔滑,您应该熟悉小程序框架的基本原则,并根据小程序框架的特征进行编写。前端代码“适合”。