xiaokeqi / i-learned

1 stars 0 forks source link

什么是fps #56

Open xiaokeqi opened 4 years ago

xiaokeqi commented 4 years ago

您了解FPS么?前端性能与其有关系么?日常开发中,我们如何根据FPS发现性能问题呢?让我们一一揭开其面纱吧~

什么是FPS

FPS全称每秒传输帧数,英文释义为:Frames Per Second

百度百科上的定义为:FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。

大白话解释:1秒内显示连续图片的数量。如30fps,一秒内显示30张连续图片。如60fps,一秒内显示60张连续图片。

接下来我们先看下不同帧率的效果

1-15fps效果:

25fps效果:

48-60fps效果:

90-120fps效果:

180fps效果:

注:此些资料参考https://zhuanlan.zhihu.com/p/48955720

从上图中我们的直观感受是:

理论上来说,fps越高,越流畅,越低越卡顿。但是计算机设备里面真的是这样么?

对于大多数显示器来说,其默认fps为60,即显示器画面的刷新率是60次每秒,如果我们在一个fps为60的显示器上,将动画渲染速度fps设置为120fps,即浏览器1秒内渲染120次,但由于显示器是60fps,因此我们只能看到60次,这浪费了60次的渲染性能。视觉上并没有流畅度加强的直观感受。

所以并不是fps越高越好,而是要根据设备的fps值,在其范围内越高越好。查看设备fps值的方法见下图:

image

前端性能

了解了fps概念后,那么fps跟前端性能有何关系呢?

通过上面我们能了解到60fps,是大部分设备的默认值,也是让我们视觉上舒适的值。那么对于浏览器,我们希望1m内渲染至少60次帧(图)是完美状态,低于60次就存在掉帧的可能。从而视觉上表现为卡顿。

1m内渲染60次,相当于16ms内完成一次浏览器的渲染。

在这一次的渲染过程中,浏览器需要完成的操作有:

image

如果此阶段中任何一个阶段耗时较长,都会导致浏览器渲染时间变长,比如如果某次渲染花了20ms时间,那么他的渲染效果不会再浏览器第一帧16ms的时候显示,这个渲染结果会在第一帧32ms的时候显示。这就是所谓的掉帧现象。当掉帧现象大量复现时,给用户的视觉直观感受为卡顿。

那么怎么排查性能问题呢?

排查性能,首先需要定位问题原因,定位问题前,我们需要在了解下主线程、合成线程和GPU在浏览器里面负责的职责所在。

主线程:

  1. Javascript 的计算与执行
  2. CSS 样式计算
  3. Layout 计算
  4. 将页面元素绘制成位图(paint),也就是光栅化(Raster)
  5. 将位图给合成线程

合成线程:

  1. 将位图(GraphicsLayer 层)以纹理(texture) 的形式上传给 GPU(GPC和CPU之间带宽)
  2. 计算页面的可见部分和即将可见部分(滚动)
  3. CSS 动画处理(CSS 动画而言,由于其流程不受主线程的影响,所以性能更好。)
  4. 发送绘图命令给GPU

GPU:

绘制图层到屏幕上

了解了上面知识后,我们需要通过chrome开发者工具定位帧耗时情况,找出耗时最长阶段。

image

如果是Scripting计算执行阶段,定位js代码是否存在迭代次数过多或者死循环的存在,可通过优化算法来解决

如果是rendering阶段,是否一次性绘制dom节点过多?因为dom节点过多,dom树构建、layout时间相应变长,造成速度变慢。一般对其优化的点是采用分页,或者按需加载显示的方式,只渲染视觉范围内dom节点。不全局渲染。

如果是Painting阶段,是否引用了代价比较高的css属性,前段时间遇到一个bug,一个小伙伴写了一个h5页面,这个h5页面在部分机型下,body滚动条不灵敏,甚至偶现滚动条抖动情况。当时一头雾水,查不出问题原因,好吧,只能一行行的删代码。却发现在删除了css文件后,页面滚动条好了!!!于是乎开始排查css,发现其用了好多代价高的样式。

目前代价高的样式有:

color,border-style,visibility,background,
text-decoration,background-image,
background-position,background-repeat
outline-color,outline,outline-style
border-radius,outline-width,box-shadow
background-size

是否存在大范围的独立layer?因为大范围的layer中的某个元素变更时,会造成整个layer的重新painting。从而时间变长。这种情况下,可以将容易造成重绘的元素,分在一个小layer中。加快绘制速度。

还可以通过开启硬件加速(gpu)来加快渲染。因为gpu只需要绘制图层,不需要经过主线程的layout、paint阶段。

开启硬件加速的方式主要有:

  1. 通过改变 opacitytransform 的值触发
  2. 通过transform的3D属性强制开启GPU加速
  3. will-change显式地通知浏览器对某一个元素的某个或某些元素做渲染优化

GPU虽然擅长处理图像,但是它也有瓶颈。连接CPU和GPU之间的带宽是有限的,如果一次更新的层太多,消耗内存,很容易就达到GPU的瓶颈,影响到动画的流畅度。

好了,今天就到这里了!

水平有限,

理解有误之处,

请指正

参考资料:

https://zhuanlan.zhihu.com/p/48955720

https://www.cnblogs.com/coco1s/p/8029582.html

https://zhuanlan.zhihu.com/p/78569750

https://blog.poetries.top/2018/11/20/performance-fps/

https://juejin.im/post/5c1c95bef265da613c09c677

https://alvabill.ml/%E5%88%B6%E4%BD%9C60fps%E7%9A%84%E9%AB%98%E6%80%A7%E8%83%BD%E5%8A%A8%E7%94%BB/