当前位置: 首页 > 科技观察

我优化了进度条,页面性能竟提高了70%

时间:2023-03-21 19:36:18 科技观察

优化了进度条,页面性能提升了70%在梳理的过程中,看到有一个进度条组件,写的非常好。这让我想起了刚开始学习前端时写的进度条代码。学者想都别想,我第一个实习公司给我带来的导师也是如此)。因此,我想与大家分享这个优秀的进度条组件。同时,它也存在着非常严重的性能问题。在本文的最后,我将解释优化方法的问题和应用场景。进度条组件一般出现在抖音播放视频这样的场景中,如图下方箭头所示:image.png进度条会随着视频的长度而增长,当视频暂停时,进度条的动画也会暂停。来看看大部分人是怎么写的,为什么说思路和表现不好。这里我们以React为例。Vue开发者不用怕看不懂。主要看思路。主要功能有:支持播放、暂停、重放。/index.jsximport{useState}from'react'import'./index.css'lettimer=null//增量进度定时器lettotalTime=3000//假设视频播放为3sfunctionApp(){const[progress,setProgress]=useState(0)//Progressconst[isPlay,setIsPlay]=useState(false)//是否播放//setProgress递增逻辑consthandlerProgress=pre=>{if(pre<100)returnpre+1;else{alert('playingover')return0//播放结束,重新开始播放}}//开始播放&&暂停播放constandleVideo=()=>{setIsPlay(!isPlay)isPlay?clearInterval(timer):timer=setInterval(()=>setProgress(handlerProgress),totalTime/100)}//重播constreplay=()=>{setIsPlay(true)if(timer)clearInterval(timer);setProgress(0)timer=setInterval(()=>setProgress(handlerProgress),totalTime/100)}return({isPlay?'Pause':'Play'}重播

)}stylepart.container{height:10px;border-radius:5px;border:1pxsolidblack;}.progress{height:100%;width:0;background-color:red;}来简单演示一下这个进度条的外观0opakkask9kklana669029.gif为什么说这种写法不太好呢?因为我们使用定时器快速递增变量progress来实现进度递增。变量每次变化都会驱动视图重新计算渲染,这肯定性能不好(说实话,我体验这个demo的时候,肉眼可见的小卡顿)还有什么?其实,滞后还有一个原因。你不妨猜一猜。我们最后再说吧。想知道答案的可以直接滑到下方推荐的写法。这里推荐的是我看代码时看到的对比。优秀的解决方案,给大家分享一下组件部分//index.jsximport{useState}from'react'import'./index.css'lettotalTime=3000//假设视频播放是3sfunctionApp(){const[isPlay,setIsPlay]=useState(false)//是否播放const[count,setCount]=useState(0)//播放次数const[type,setType]=useState(0)//使用哪个动画0:@keyframesplay;1:@keyframesreplay;//暂停&&播放constandleVideo=()=>setIsPlay(!isPlay);//重播constreplay=()=>{setIsPlay(true)setType(type?0:1)}//动画结束时触发的事件constend=()=>{setCount(count+1)//播放次数+1replay()//重新开始播放}return({isPlay?'Pause':'Play'}Replay{`播放次数:${count}`}
)}样式部分@keyframesplay{to{width:100%;}}@keyframesreplay{to{宽度:100%;}}.container{height:10px;border-radius:5px;border:1pxsolidblack;}.progress{height:100%;width:0;background-color:red;animation-timing-function:linear;}.progress.play{/*makeanimation动画开始*/animation-play-state:running;}.progress.pause{/*makeanimationanimationanimationispaused*/animation-play-state:paused;}我们设置了两个@keyframes动画,用来在进度条回放时进行切换,即点击“Replay”时,可以直接切换到另一个动画.进度条可以从0开始递增。同时我们还设置了两个类名的样式,用于控制动画的播放和暂停。当播放完成后,可以通过事件animationend监听播放次数+1的函数。同样,我们来看一下这套方案的效果图(功能与上一套方案完全一样)系统中大量的计算,改善了很多性能缺陷。第二种方案虽然性能不错,但和第一种方案一样,还有一个隐藏的性能问题。这是我在查看以前同事的代码性能问题时发现的。缺陷:两种方案都会造成频繁的重排和重绘。可以使用chromedevtoolsperformance来验证页面的情况。效果如何?我们简单回顾一下重排和重绘Reflow的影响:浏览器需要重新计算元素的几何属性,其他元素的几何属性或位置也可能受到这种变化的影响。重绘:并非所有DOM更改都会影响元素的几何属性。如果改变元素的背景色不影响它的宽高,这种情况下只会发生一次重绘,不会发生重排,因为元素布局的布局没有改变,所以在知道问题严重后重排重绘造成的,我们马上分析优化,极致优化。.当然,也有一些方法可以跳过一些中间步骤,比如避免Layout和Paint。回顾一下哪些方法会引起重排和重绘。触发重排的因素:增加或删除可见DOM元素,改变元素位置,元素大小变化(包括:外边距,内边距,边框,高度等),内容变化(如:文字变化或图片被替换)另一张不同尺寸的图片),浏览器窗口大小变化,隐藏一个DOM节点触发重绘的因素:重排必须触发重绘(重要),通过可见性隐藏一个DOM节点:隐藏,修改元素背景色,修改字体颜色等等那么我们之前写的代码中的trigger在哪里呢?重新排列和重新粉刷怎么样?简单查看后不难发现,这两种方案都是在不断改变元素的宽度。元素的宽度发生变化,必然会引起重排重绘,更何况超频繁的变化!解决方案:开启GPU加速,避免重排和重绘,将进度条提升到单独的一层,即在不影响其他元素的情况下针对方案二进行优化~我们只需要改变它的css内容就可以了(标示的是改变)@keyframesplay{/*通过transform启用GPU加速,跳过重排和重绘阶段*/0%{transform:translateX(-50%)scaleX(0);/*使用scaleX代替width*/}来{transform:translateX(0)scaleX(1);}}@keyframesreplay{0%{transform:translateX(-50%)scaleX(0);}to{transform:translateX(0)scaleX(1);}}.container{height:10px;border-radius:5px;border:1pxsolidblack;}.progress{height:100%;width:100%;/*初始宽度为100%,因为我们要对其进行缩放*/background-color:red;will-change:transform;/*通过will-change*/animation-timing-function:linear;}.progress.play{animation-play-state:running;}.progress.pause通知浏览器提前做好优化准备{动画ion-play-state:paused;}这里简单解释一下translateX和scaleX的值设置。设置进度条宽度:100%。我们通过scaleX(0.5)将其缩放一半,可以发现进度条的长度是容器的一半,并且居中。此时我们需要通过translateX(-25%)将它平移到最左边,为什么是-25%呢?因为进度条占了容器的一半,并且居中,表示左右空白正好是(100%\-50%)/2=25%,所以不难知道translateX的值是什么时候初始状态scaleX(0)对-(100%\-0%)/2=\-50%执行此操作后,我们再次检查kasjdaskdj0022asd69029.gif的性能,我们可以清楚地看到页面重新排序和重绘的次数减少了很多,剩下的就是最基本的页面重排和重绘。有人要说我是头条党。接下来,我将向您展示优化了多少性能。首先,用刚刚优化到极致的那个运行performanceimage.png。看图片的右侧。FPS基本稳定在55~70之间,我们再来看看文开头第一个方案的性能跑分image.png看右图。FPS基本稳定在32-50之间,可以明显看出优化前的FPS波动非常严重,也就是不够稳定,容易出现卡顿问题;优化后FPS变化不大,整体变化趋势比较平缓,几乎是一条直线。在这样一个极简的页面中,我们优化后的性能提升了大约40%~54%。那么如果在正常的项目中,考虑到页面的复杂性,我们的优化方案不仅避免了页面的重复计算和渲染,也避免了重绘和重排。可以想象,那种情况下的性能提升应该是遥遥无期的。40%~54%多,emmmmmmm,所以我说70%的性能提升应该不会太多吧?Hhhhh小复活节彩蛋。启用GPU加速会将元素提升到一个单独的层。我们可以通过chromedevtoolslayers.png查看图片,这里展示一下优化前后我们页面的层次感。"image.png也能看得很清楚,进度条被单独分开了一层