腾讯WeTest 微信小程序之提高应用速度小技巧

腾讯WeTest · 2017年03月10日 · 2020 次阅读

作者:vicyao, 腾讯 web 前端开发 高级工程师
商业转载请联系腾讯 WeTest 获得授权,非商业转载请注明出处。
原文链接:http://wetest.qq.com/lab/view/294.html

WeTest 导读

小程序科普类的文章已经很多了,今天这里讲的是针对小程序的优化方法,可以有效提高小程序的响应速度和用户体验。当然,开发体验也提高不少。


1、提高页面加载速度

在小程序这个环境下,怎样提高页面加载速度呢? 这个问题很大,我把问题具体一下,如何缩短从用户点击某个链接,到打开新页面的这段时间? 这里抛一个核心关键点:

从页面响应用户点击行为,开始跳转,到新页面 onload 事件触发,存在一个延迟,这个延迟大概在 100-300ms 之间(安卓响应比 ios 慢些)。

这个延迟说短不短,我们可以利用这段时间,预先发起新页面所需要的网络请求。这样一来,就节省了 100-300ms(或者一个网络请求的时间)。

知道有这个 gap 后,代码如何实现呢?

说白了,就是实现一个在 A 页面预加载 B 页面数据的功能。但而这种跨页面的调用,很容易把逻辑搞复杂,将不同页面的逻辑耦合在一起。所以,我们希望将预加载的逻辑隐藏于无形中,不增加任何的页面间耦合,以及开发复杂度。

下面以腾讯视频小程序为例,讲解下技术实现。

小程序首页:

当用户点击海报图后,会执行以下代码(就一行):

接下来程序会加载播放页:

播放页主要代码:

可以看到,不管是外部页面的调用还是实际逻辑的实现都非常简洁。在第二个页面中,我们扩展了 Page 的生命周期函数,增加了 onNavigate 方法。该方法在页面即将被创建但还没开始创建的时候执行。

老司机也许会发现这里有点蹊跷。在首页点击的时候,播放页根本就没有创建,对象都不存在,怎么访问到里面的方法呢?

这里就要说下微信的页面机制。

在小程序启动时,会把所有调用 Page() 方法的 object 存在一个队列里(如下图)。每次页面访问的时候,微信会重新创建一个新的对象实例(实际上就是深拷贝)。

也就是说,在 A 页面在执行点击响应事件的时候,B 页面的实例还没创建,这时候调用的 onNavigate 方法,实际上是 Page 对象的原型(小程序启动时候创建的那个)。

而接下来马上要被创建的 B 页面,又是另外一个 object。所以,在 onNavigate 和 onLoad 方法中,this 指针指的不是同一个对象,不能把临时数据存储在当前 object 身上。因此我们封装了一对全局的缓存方法,$put() 和 $take()。

为了通用性,Page 上用到的公共的方法,比如 $route、$put、$take 都定义在了一个 Page 的基类里面。基类还同时保存了所有页面的 list,这样就可以做到根据页面名调用具体页面的 onNavigate 方法。 当然,并不是每个页面都需要实现 onNavigate 方法,对于没有定义 onNavigate 方法的,$route 函数会跳过预加载环节,直接跳转页面。所以对于开发者来说,不需要关心别的页面实现了什么,对外看来完全透明。

2、用户行为预测

在上面的例子中,我们实现了用户主动点击页面,提前加载下一页面数据的方法。而在某些场景下,用户的行为可以预测,我们可以在用户还没点击的时候就预加载下个页面的数据。让下个页面秒开,进一步提升体验的流畅性。

继续以腾讯视频小程序为例,主界面分为 3 个页卡(大部分小程序都会这么设计),通过简单的数据分析,发现进入首页的用户有 50% 会访问第二个页卡。所以预加载第二个页卡的数据可以很大程度提高用户下个点击页面的打开速度。

同样,先看看代码实现。 首页预加载频道页的姿势:

频道页的实现方法:

跟第一个例子类似,这里定义了一个 $preLoad() 方法,同时给 Page 扩展了一个 onPreload 事件。页面调用 $preLoad() 后,基类会自动找到该页面对应的 onPreload 函数,通知页面执行预加载操作。 跟第一个例子不同,这里预加载的数据会保存在 storage 内,因为用户不一定会马上访问页面,而把数据存在全局变量会增加小程序占用的内存。微信会毫不犹豫的把内存占用过大的小程序给杀掉。

也许对于大部分有 app 开发经验的同学来说,更普遍的做法是先让页面展示上次缓存的数据,再实时拉取新数据,然后刷新页面。这个方法在小程序上也许体验并不太好,原因是小程序的性能以及页面渲染速度都不如原生 app。将一个大的 data 传输给 UI 层,是一个很重的操作。因此不建议采用这种方法。

3、减少默认 data 的大小

刚刚说到,页面打开一个新页面时微信会深拷贝一个 page 对象,因此,应该尽量减少默认 data 的大小,以及减少对象内的自定义属性。有图有真相:

以一个 100 个属性的 data 对象为测试用例,在 iphone6 上,页面的创建时间会因此增加 150ms。

4、组件化方案

微信没有提供小程序的组件化方案(相信一定在实现中)。但开谈不说组件化,写再多代码也枉然。这里演示一个简单的组件化实现。

以腾讯视频播放页为例,页面定义如下:

其中,P() 函数是自定义的基类。这是一个非常有用的东西,可以把所有通用的逻辑都写在基类里面,包括 pv 统计,来源统计,扩展生命周期函数,实现组件化等。

函数第一个参数是页面名称,作为页面的 key。第二个是 page 对象,其中扩展了一个 comps 数组,里面就是所有要加载的组件。

以播放器组件/comps/player/index.js 为例:

组件的定义跟一个普通 Page 对象一模一样,有 data 属性,onLoad、onShow 等事件,也有页面响应的回调方法。wxml 模板里定义的事件和 js 事件一一对应。

基类做的事情,就是把这些组件对象的属性和方法复制到 Page 对象上(浅拷贝)。其中 data 属性会 merge 到一起。而微信预定义的生命周期函数(包括自己扩展的),则封装成队列按序执行。比如当系统调用 onLoad 方法时,实际上是执行了所有组件的 onLoad 方法,最后再执行 Page 的 onLoad。

以上是代码部分,至于 wxml 模板和 wxss 部分,就要手工 import 过去了。

wxml:

wxss:

5、其他

虽然小程序已经足够小巧,但启动速度还是有那么 2-3 秒,无法做到秒开。楼主尝试对小程序的启动时间做优化,但没有找到多少有价值的优化点。单个页面的初始化只需要 1-2ms。也许大部分时间消耗在了微信跟服务器端通信的过程中。

所幸,腾讯提供了一个可以自主进行服务器性能测试的环境,用户只需要填写域名和简单的几个参数就可以获知自己的服务器性能情况,目前在腾讯 WeTest 平台可以免费使用。

腾讯 WeTest 服务器性能测试运用了沉淀十多年的内部实践经验总结,通过基于真实业务场景和用户行为进行压力测试,帮助游戏开发者发现服务器端的性能瓶颈,进行针对性的性能调优,降低服务器采购和维护成本,提高用户留存和转化率。

功能目前免费对外开放中,欢迎大家的体验!

体验地址:http://wetest.qq.com/gaps

如果对使用当中有任何疑问,欢迎联系腾讯 WeTest 企业 qq:800024531

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册