本文稍有啰嗦,主要是记录下思路,啰嗦就啰嗦点吧哈哈
遇到的问题
最近在开发小程序的过程中遇到一个问题,在苹果手机上,小程序的首页在首次加载完后会出现三四秒的卡顿,此时任何的页面交互都卡卡的,操作不顺畅,过去个三四秒后才恢复正常。安卓手机上确很流畅,可能安卓的手机性能超越了苹果吧。但我的手机是苹果,对于经常使用各种应用的我来说,页面加载完过三四秒才能操作,是绝对不能忍的,何况是用户...
思路
首页的接口确实挺多的,一开始以为是接口太多,数据太多造成的卡顿,试着去屏蔽掉一些确还是如此(内心充满了疑惑ing...),偶然在重构另一个页面时,发现了猫腻。重构的是一个商品分类页面,左边是上下滑动的分类标签,右边展示对应标签查询出的商品列表,使用了对象数组存储每个分类标签下的相关数据,结构如下:
data: {
pageData: [], // 存储每个分类对应的数据
defaultParams: { //pageData数组对应的对象数据结构
categoryId:'',//分类ID
list: [] //存储商品列表
//其他字段
requesting: false,
end: false,
empty: false,
pageNum,
pageSize: 20,
},
}
复制代码
之所以使用了数组,为的是存储点击对应分类后请求的接口数据,当重复点击某个点击过的分类时,不用再次请求接口,根据分类索引从数组中取商品列表直接渲染即可,是一种优化手段。
分类页
可以看到分类页点击标签后的交互,第一次是加载数据,第二次再回去点击直接显示出列表内容
说这么多是因为首页也是由分类和商品列表两部分组成的,而存储的数据也是pageData,俩页面如此相似,分类页却没有卡顿的问题。作为主角的首页,当然要比分类页要多点骚操作才能显示出它的地位,而这个骚操作就是左右滑动整个页面来切换分类模块
首页
分类页只有点击分类标签切换,没有滑动的交互。
而左右滑动切换模块用到的是swiper组件,分类的数据大约20个左右,也就是说需要初始化20个swiper-item,它里面包含的内容就是商品列表,在微信开放社区搜了下这个组件,果不其然大家都遇到了这个组件数量太多页面卡顿的问题。一开始并没有立马怀疑swiper,有一个关键点让我慢慢接近这个怀疑对象:分类页的pageData在页面初试完后并没有根据分类的个数初始化完所有的数据,也就是说首页上有20个分类,就初始化了20个数组元素,而是在分类标签点击后初始化对应索引下的数据,因为没有必要初始化所有的。
这里就与首页的不同了,翻了翻首页的代码,发现居然上来就初始化了所有的数据,首页除了这个分类商品列表,没有比这数据更多的内容了,会不会是因为这个pageData呢,顶着一个大大的问号和一点点零星的期待,去修改了首页的初始化逻辑,改成与分类页一样,点击分类后初始化pageData索引下的数据,果不其然跟我预料的一样,页面加载完后不卡了,立马点击滑动啥的操作也变得无感,吼吼好开心,终于让我逮到原因了,原来是这个pageData数组数据太多导致的呢,
二话不说,改成跟分类一样的初始化逻辑即可,but....问题也随之出现,点击分类导后倒是没问题,但忽略了页面左右滑动这个交互,然后就.....滑不动了(内心苦涩.....),就像这样:
滑不动是因为数据未初始化,从而导致swiper-item未渲染,swiper只有在swiper-item有的情况下才能滑动.....这就尴尬了,这跟点击哪个初始化哪个的方法冲突了。
解决方法
既要保证pageData数组元素初始化的少,又要保证左右滑得动,用分页的方法或许可以,经过我一番各种尝试,终于有了结果。好了,不啰嗦,说下思路吧:点击分类tab或滑动swiper时都需要初始化并加载数据, 点击分类tab会触发一个点击事件,滑动swiper会触发滑动事件,那就在这两个事件触发时初始化pageData,而整个页面初始化后可以先加载三四个swiper-item(因业务逻辑不同,我这里试过页面一开始只加载三四个时还是不卡的)
看下方法:
data:{
current: 0,//选中的分类索引
pageTypes: [{name:'',id:'',index:0}],//分类数据
pageData: [], //列表数据
defaultParams: { //pageData里的对象
categoryId: '',
requesting: false,
end: false,
empty: false,
pageNum,
pageSize: 20,
list: []
},
},
//初始化当前的分类tab与前一个后一个的数据,current是选中的分类tab的索引
_loadRemainPageData(current) {
const { pageTypes, pageData, defaultParams } = this.data
//根据选中的分类索引,取前后范围,截取分类数组,用这段数组来初始化pageData
let typeFragment = pageTypes.slice(current - 1, current + 2)
let addNum = 0
typeFragment.forEach(item => {
//pageType的数据里有索引值index,它与pageData是一一对应的,所以可以取出来初始化对应的数据
if (!this.data.pageData[item.index]) {//防止重复初始化
addNum++ //记录每次截取pageType后初始化的个数,初始化过后不会走这
pageData[item.index] = {
...defaultParams,
categoryId: item.id
}
}
})
if (addNum > 0) this.setData({ pageData })
}
复制代码
这个方法用在这两个事件里:
//分类tab切换事件
hanldeTabType(e) {
let { index, item } = e.detail
this.setData({
current: index,
categoryId: item.id,
})
let currentPageData = this._getCurrentData()
//点击分类tab切换页面时去初始化pageData对应索引下的值
if (!currentPageData) {
this._loadRemainPageData(index)
currentPageData = this._getCurrentData()
if (currentPageData.list.length === 0) this._getSpuList('refresh', pageNum)
}
},
//页面滑动事件
handleAnimationFinish(e) {
const current = e.detail.current
this.setData({
current,
})
this._loadRemainPageData(current)
let curpageData = this._getCurrentData()
if (curpageData.list.length === 0) this._getSpuList('refresh', pageNum)
},
/**
* @description: 获取当前激活页面的数据
* @param {*}
* @return {*} 当前索引对应的数据
*/
_getCurrentData() {
return this.data.pageData[this.data.current]
},
复制代码
这两个事件去执行初始化方法,不论是从前往后点击分类,还是点击分类的倒数第几个,都能保证pageData对应的数据初始化完成,swiper也能一直滑得动。滑不动的问题解决了,也用分页的方法解决了卡顿问题,但
当数据量非常多的时候且从分类的倒数第几个点击时,还是会因为pageData太多在点击之后卡顿,因为,比如点击倒数第19个时,pageData的数据是这样的:
而渲染后的DOM是这样的:
因为数组的长度变了,还是会渲染swiper-item, 在微信社区看到一篇文章,把没有显示出来的DOM尽量简化,用空的swiper-item替代之前复杂的那个
这样就更快了,页面初始化完后,点击倒数几个分类出现的卡顿也基本无感了
小结
不过当数据非常多时,点击倒数第几个分类时还是会有卡顿的问题,但以上方法足以解决线上很卡的性能问题。嗯...目前还没想到更好地方法,若有更好地方法希望大家可以分享出来互相学习嘻嘻
有新发现
在做一个H5页面时,也遇到了需要使用很多swiper的情况(说的是swiper滑块很多...),这次swiper的每个滑块中包含的是一个Echarts图表,当数据少时页面加载完后手指滑动swiper时还是可以的,当数据量多时,整个页面就卡住了,先来看下这个页面吧
(此处啰嗦一哈:看起来并不是我说的很卡对吧,那当然是我优化后的样子啦哈哈,至于卡顿的就不拿出来了,因为页面是不动的,就算有动图看起来也是个截图的样子🐶)
温度与湿度两个模块组件中,分别使用了两个swiper,每个swiper中有11个滑动容器,再加上内容是Echarts,页面肯定会很卡。优化后的页面看起来流畅多了,页面初始化时依然初始化了很多数据来渲染swiper滑块,且这次并没有用上次那么复杂的方法,而是把滑块中的内容做了if判断,滑块组件正常渲染即可,内容在当前滑块所处的index与数据list的index相等时才渲染,也就是说除了当前index的滑块,其他滑块的内容都是空的
数据多时导致页面卡顿的原因当然与数据多少有很大关系,但主要的原因还是滑块中的内容,内容多且DOM复杂时卡顿就很明显了,一两个看不出来,五六个时就明显了,为啥这么说呢,因为我试着把滑块中的内容用最简单的文字作为替代,发现虽然同样滑块很多,但页面依旧很流畅,如下:
这次虽然不是小程序的swiper,但也有着同样的问题,而这次的问题与上次小程序页面稍有不同,上次小程序是逐渐把数据分页填充,最后即时有很多滑块包括滑块内容复杂,页面只要渲染过一次后便可以流畅操作,而这次就算页面初始化后好久也一直卡顿,整个页面就像崩了一样~~上次的方法用在这次显示不合适喽....
还是要根据实际情况选择合适的解决方法,嗯,这次就说这么多吧,说不定哪天我又会发现更不错的解决方法了嘿嘿(2022-11-05记)
好记性不如烂笔头,还是选择记录一下,哪天估计又忘记了🐶
总结文章挺耗时间的,看完觉得有用可以给个小小的赞奥,比心 ^-^