Description
一、原有mpvue更新机制的不足和影响
mpvue实现原理是基于Vue2.js,重写platform部分代码来实现在小程序环境下用Vue组件系统进行运行。在Vue的H5实现中,当我们组件树上的一个组件属性更改后,会触发整个树的检查更新,然后在新老dom树对比算出最小改动后,同步到浏览器的真实dom,这个过程熟悉Vue的开发者很熟悉了,就是diff更新。
但是H5版的diff最后的浏览器runtime代码是基于增删dom节点API进行的,小程序又不提供增删节点的功能,所以为了能在小程序环境实现更新,原版mpvue对整个触发更新检查的V-dom树都取值转换成了小程序对应的JSON,通过setData()接口同步到视图。这个过程在实际运行会造成setData的数据冗余过大。通过代理updateDataToMP打日志的方式我们发现,v-dom树上任意节点的任意属性更改,会引发整棵树的更新,一次形如this.a = 1的操作会引起O(N^2)量级的更新。真实在项目中监控到,一个10个组件左右构成的页面,每次进行一次this.a=1数据更新,在$nextTick渲染时真实传到小程序的数据大概在10k-20k。安卓真机上会造成大概200-300ms的渲染演示,肉眼能较明显觉察。
二、新mpvue更新机制原理和效果
新版Mpvue在每次数据更新的时候,会在Vue监听set方法,每次触发属性更新的时候把当前更新的属性key放在当前V-dom的__keyPath属性中。一次更新全部触发后,在实际render过程中遍历keyPath属性,只选择更新的属性放到json里,调用Page.setData来进行更新操作。同时在Vue.$nextTick函数里,触发完所有的render更新后会清理掉全部keyPath,防止下次再更新又冗余。通过这种操作,this.a=1可以O(N^2)量级降低到O(1).上面例子中每次更新10k-20k的页面,在业务中有比如用户操作引起某个组件数字+1,关闭弹窗等操作时,更新量降低到几个字节。安卓卡顿的问题也从框架角度完美解决
三、新的监测机制
由于Vue实现机制,对于v-if显示/删除节点,v-dom是会进行删除操作,无法跟踪检查,所以目前还是会触发v-if的节点及其子节点从v-if=false 变成v-if=true时无法减少更新量。为了开发者们更好的评估自己页面的性能找到优化点,新版Mpvue添加了Vue.config._mpTrace属性,把这个属性置true的情况下可以看到console里会打印每500ms更新的数据量,帮助你结合真机表现彻底解决卡顿等性能问题。
注意,监控方法依然是通过JSON.stringfy(data)实现,线上代码不要出现否则会有额外性能损失