在微信小程序的开发过程中,发现部分页面的切换动画在真机调试时,非常卡顿。
页面切换是指从一个页面,切换到另外一个页面。
反复查看了自己的代码,也没有发现自己写了任何非常耗时的操作,因此非常迷惑。
思考了多种方案没有效果,于是在网上找了一种说法,一篇文章说,在全局样式中新增如下属性,就可以解决。
page {
-webkit-overflow-scrolling: touch;
}
病急乱投医试了一下,很可惜没有效果。后来想起来了这条属性是用来解决 iOS 使用 overflow: scroll 滚动不流畅的问题的。
于是,在没有头绪的情况下,我启用了我的找 bug 的终极大招:删除定位法。
删除定位法:先删除部分代码,再执行页面,查看卡顿问题是否消失。如果没有,则删除其他部分的代码,直到找到问题代码为止。
该方法在我的十多年中,所向披靡,战功显赫。果不其然,我最终找到了问题所在。
在该页面组件中,我写了这样一段代码。
useEffect(() => {
ad.current = Taro.createRewardedVideoAd({
adUnitId: ads.ad15
})
...
}, [])
在微信小程序中,createRewardedVideoAd 方法是用来提前创建激励广告实例,以便于读者在点击按钮观看广告时,广告已经创建好了,而不用等待那么久。
很显然,该方法是一个耗时操作。页面如下:
但是这里一个很具有迷惑性的地方在于,实际上我调用该方法的时机,已经在组件创建完成之后了。
useEffect(() => {
// 组件创建完成之后
}, [])
因此,我就有点懵了,为什么组件创建完成之后调用该方法,还是会卡顿呢?
后面从结果反推之后,我才想明白,微信小程序页面切换到详细逻辑应该是。
1. 创建新页面实例
2. 执行入场动画 「问题是入场动画卡顿」
那么此时如果我们在页面实例创建完成之后立马执行一个耗时任务,就会跟入场动画抢占主线程资源,从而导致渲染卡顿。
想明白了这个过程之后,解决的办法就非常简单了,我们只需要在入场动画执行结束之后,再执行耗时任务即可。因此,我们可以使用定时器来推后耗时任务的执行。
useEffect(() => {
setTimeout(() => {
ad.current = Taro.createRewardedVideoAd({
adUnitId: ads.ad15
})
}, 200)
...
}, [])
再保存,重试,发现所有卡顿的页面都流畅了!完美解决。
在客户端开发的过程中,还有可能会遇到另外一种情况会导致页面卡顿。不过这种情况与我这次遇到的这个卡顿的表现会有点不太一样。这种情况的表现为:
当我点击按钮之后,过了很长时间切换动画才开始执行。
通常情况下,造成这种卡顿的原因是因为页面初始化时执行的逻辑过多,或者渲染的内容多过,导致初始化时间过长,从而造成反应缓慢。解决的办法就是通过懒加载延后处理和渲染非首屏内容。
总结
该场景的问题与解决方案可以当做项目亮点在面试中去介绍。无论是找到问题的思路,还是解决的思路都可以展开聊很多。
对于浏览器的渲染机制和事件循环了解非常深刻的朋友可以快速想明白卡顿的原因所在,在面试中,基于这个场景延展出来自己对渲染原理的理解,那么你的面试过程将会非常有质量。