Perfeye 画廊卡顿优化
Perfeye 画廊卡顿优化
背景
某天,接到了一个反馈,项目组觉得Perfeye画廊组件很慢,每次切换都要卡顿很久,特别是在某些(性能不行)笔记本上面,经常出现卡死的情况,严重影响了他们的工作效率。老板对这个问题很重视,让尽快优化下。
原因
经过排查、测试,发现卡顿都是发生在 数据量比较大的报告上面,时长在1个小时以上的报告,每次切换 画廊小图 或者拖动 画廊FPS 时间轴,都会导致页面卡个3~5秒左右,特别是项目组给发了一份5小时的报告,我尝试拖动了一次,卡顿了15秒左右,在一些电脑上,页面直接崩溃。看来这个问题确实挺严重的,那就尽快优化吧。
图表卡顿
经过排查,发现是因为画廊与所有的图表联动导致的,页面图表很多,有十几个图表,每个图表都有相同的事件 点选、刷选,切换图片会导致 触发 点选 事件,导致所有图表重渲染引起卡顿。
画廊性能差
画廊使用的是第三方组件,在遇上大量略缩图的情况下,会全部的渲染在dom里面,每次切换画廊的时候,都会导致重绘,也会引起卡顿
优化
第一波优化
请求并发
页面初始化的时候加载图表的接口也很耗时,这里将对比页面的请求改为了并发,减少了一部分的耗时
使用懒加载
所有的图表使用React.lazy
的方式懒加载,减少首次加载时间
全局状态解耦
在画廊组件打开后,只能看到一个FPS图表,这个图表的状态其实可以单独维护,与外面的图表状态只用在开启画廊和关闭的时候同步下就可以了
经过以上步骤的优化,5小时报告画廊的切换时间已经减少到3~5秒了,可以初步满足使用了
第二波优化
自定义画廊组件
经过上面的排查,发现第三方画廊组件也有一定的性能问题,那怎么处理呢,这里想到的是虚拟列表方案,于是我尝试自己实现了下
我的思路是这样的
首先根据当前点击的index拿到30张图片,例如 index 0, 0-30 ,index 30 15-45,这样的,需要对前后进行处理下
const getVirtualItems = (items: ImageItem[], currentIndex: number) => {
const startIndex = Math.max(currentIndex - 15, 0);
const endIndex = Math.min(startIndex + 30, items.length);
return items.slice(startIndex, endIndex);
};
给每个小图的宽度为140px,然后根据当前点击的index来计算left的偏移距离,以实现移动效果
const getTranslateX = () => {
const vIndex = virtualItems.findIndex(i => i.index === currentIndex)
let translateX = vIndex * 140;
// 边缘宽度
const edgeWidth = 100 + 140
const contentWidth = window.innerWidth - edgeWidth
// 元素宽度居中
// 左边最多 占据一半屏幕个元素
const leftMaxWidth = Math.floor((contentWidth / 2)) - (edgeWidth / 2)
// 左侧剩余元素宽度
const leftWidth = (currentIndex - 1) * 140
// 右侧剩余元素宽度
const rightWidth = (items.length - currentIndex) * 140
if ((contentWidth / 2) > rightWidth) {
translateX = translateX - (contentWidth - rightWidth)
} else {
// 加上左边偏移宽度
translateX = translateX - Math.min(leftMaxWidth, leftWidth)
}
translateX = translateX * -1
return translateX;
}
这里主要复杂的地方就在于偏移量的计算,需要对 开头和结尾做一些计算处理
自定义画廊其他的api都和原有api一样,不进行变动
经过以上处理,5小时报告点击画廊切换时间不到1秒,已经完成了优化
大图组件更换
大图组件也更换为可拖动的组件,方便用户在放大后能拖动,查看到画面的不同细节