显示器显示图像的原理?
每个显示器都有固定的刷新频率,通常是60HZ,也就是每秒更新60张图片,更新的图片都来自于显卡中一个叫前缓冲区的地方,显示器所做的任务很简单,就是每秒固定读取60次前缓冲区中的图像,并将读取的图像显示到显示器上。
显卡的作用是什么?
显卡的职责就是合成新的图像,并将图像保存到后缓冲区中,一旦显卡把合成的图像写到后缓冲区,系统就会让后缓冲区和前缓冲区互换,这样就能保证显示器能读取到最新显卡合成的图像。通常情况下,显卡的更新频率和显示器的刷新频率是一致的。但有时候,在一些复杂的场景中,显卡处理一张图片的速度会变慢,这样就会造成视觉上的卡顿
帧和帧率的概念?
大多数设备屏幕的更新频率是60次/秒,这也就意味着正常情况下要实现流畅的动画效果,渲染引擎需要每秒更新60张图片到显卡的后缓冲区。
我们把渲染流水线生成的每一幅图片称为一帧,把渲染流水线每秒更新了多少帧称为帧率,比如滚动过程中1秒更新了60帧,那么帧率就是60Hz(或者60FPS)
渲染引擎是如何实现一帧图像的?
实现一帧图像的方式有重排、重绘和合成三种方式
这三种方式的渲染路径是不同的,通常渲染路径越长,生成图像花费的时间就越多。
- 重排:它需要重新根据 CSSOM 和 DOM 来计算布局树,这样生成一幅图片时,会让整个渲染流水线的每个阶段都执行一遍,如果布局复杂的话,就很难保证渲染的效率了。
- 重绘:因为没有了重新布局的阶段,操作效率稍微高点,但是依然需要重新计算绘制信息,并触发绘制操作之后的一系列操作。
- 合成:相较于重排和重绘,合成操作的路径就显得非常短了,并不需要触发布局和绘制两个阶段,如果采用了 GPU,那么合成的效率会非常高。
PS: 按照效率,推荐合成方式优先
浏览器是如何实现合成的?
Chrome中的合成技术,可以用三个词来概括总结:分层、分块和合成。
需要重点关注的是,合成操作时在合成线程上完成的,这也就意味着在执行合成操作时,是不会影响到主线程执行的。这就是为什么经常主线程卡住了,但是CSS动画依然能执行的原因。
CSS动画比JavaScript动画高效的原因是什么?
当对某个元素做几何形状变换、透明度变换或者一些缩放操作时,如果使用JavaScript来写这些效果 ,会牵涉到整个渲染流水线,所以JavaScript的绘制效率会非常低下。可以使用 will-change
来告诉渲染引擎你会对该元素做一些特效变换,好处见下。
如何使用will-change来优化动画或特效?
.box {
will-change: transform, opacity;
}
这段代码就是提前告诉渲染引擎 box 元素将要做几何变换和透明度变换操作,这时候渲染引擎会将该元素单独实现一帧,等这些变换发生时,渲染引擎会通过合成线程直接去处理变换,这些变换并没有涉及到主线程,这样就大大提升了渲染的效率。这也是 CSS 动画比JavaScript 动画高效的原因。
劣势:通过will-change来提前告诉渲染引擎,让它为该元素准备独立的层带来的坏处是:它占用的内存也会大大增加,因为从层树开始,后续每个阶段都会多一个层结构,这些都需要额外的内存,因此需要恰当地使用will-change.