- 需求的场景描述(希望解决的问题)
我们的小程序比较复杂,嵌套使用了很多自定义组件,自定义组件间传递的数据有些是较大的对象。现在发现性能很差,用户经常反馈卡顿闪退,做性能分析的时候提示过多地调用了setData,但其实我们的setData并不多,只是自定义组件层级多而已。
我理解是不是因为自定义组件的数据传递机制有点问题?
举个例子:页面A中使用了自定义组件C1,自定义组件C1中又使用了自定义组件C2 …
自定义组件的数据传递机制是不是这样的:
1、页面A通过调用setData,把A的数据stringify后传递给了页面A的wxml(从js线程 -> 渲染线程)
2、页面A的wxml发现使用了组件C1,于是把要传递给C1的数据parse之后传递给C1的js线程(从渲染线程 -> js线程)
3、组件C1的js接收到数据之后,需要把数据传递给组件C1的wxml,于是又stringify一次(从js线程 -> 渲染线程)
4、组件C1的wxml发现使用了组件C2,于是把要传递给C2的数据parse之后传递给C2的js线程(从渲染线程 -> js线程)
5、组件C2的js接收到数据之后,需要把数据传递给组件C2的wxml,于是又stringify一次(从js线程 -> 渲染线程)
如此类推。。。。。。
我的问题是:
1、我理解的数据传递过程对么,是这样实现的吗?(代码片段里做了个简单的验证,同一份数据传递之后确实不一样了)
2、如果1的假设是对的,那可不可以通过用app.globalData.xx之类的方式来做数据传递呢?要setData的数据放到app.globalData.xx里,然后在自定义组件中去监听app.globalData.xx的变化(js线程 -> js线程),是不是可以节省下一趟的stringify、parse的开销?
3、如果2的假设是对的,getApp的开销有多大,是不是可以忽略不计的?
4、如果上面的假设没错,那这是不是做性能优化的一个思路呢?
不,你的理解完全不对。自定义组件的数据传递没有跨线程调用。会有对象深复制,但是除非你传的属性真的非常非常复杂、传递的层数非常多,这里的开销很难达到“卡顿”、“闪退”的程度(所以我不建议先从这个角度开始排查)。如果你要尝试避免深复制来看看优化效果的话,可以考虑将数据传递的方式改为 selectComponent 来直接传递(但我真的不建议先尝试这个)。
通常卡顿、闪退的问题,通常是因为页面的总节点数量太大,达到数千个,低端机难以处理。
如果怀疑和 setData 调用有关的话,还有另一种可能的原因:有些时候有过多的 setData 被间接触发,导致计算量很大甚至死循环或者无限递归。比如,一次 setData 触发了子组件的生命周期或者 observer 等,导致子组件触发一个事件返给父组件,父组件处理事件时又再次 setData ,类似这样的过程发生很多很多次,就会出现卡顿之类的情况。