-
动画效果尽量使用
requestAnimationFrame
而不是使用setTimeout
或者setInterval
-
由于
JS
是单线程运行,请将需要耗费大量时间运行的任务放到Web Worker
进行执行。 -
请使用微任务来进行
DOM
更改,如果你不了解什么是微任务,请点击这里 -
使用
Chrome DevTools
的Timeline
和JavaScript
分析器来评估 JavaScript 的影响
使用requestAnimationFrame
大多时候,我想大部分人执行一个动画效果都会用到 setTimeout
或者 setInterval
这两个函数,但是这两个函数和requestAnimationFrame
有什么区别呢,似乎用下来感觉差不多?
这要从屏幕刷新率说起。
屏幕刷新频率
屏幕刷新频率,即图像在屏幕上更新的速度,也即屏幕上的图像每秒钟出现的次数,它的单位是赫兹(Hz)。 对于一般笔记本电脑,这个频率大概是60Hz。
因此,当你对着电脑屏幕什么也不做的情况下,显示器也会以每秒60次的频率正在不断的更新屏幕上的图像。为什么你感觉不到这个变化? 那是因为人的眼睛有视觉停留效应,即前一副画面留在大脑的印象还没消失,紧接着后一副画面就跟上来了,这中间只间隔了16.7ms(1000/60≈16.7), 所以会让你误以为屏幕上的图像是静止不动的。而屏幕给你的这种感觉是对的,试想一下,如果刷新频率变成1次/秒,屏幕上的图像就会出现严重的闪烁,这样就很容易引起眼睛疲劳、酸痛和头晕目眩等症状。
动画原理
根据上面的原理我们知道,你眼前所看到图像正在以每秒60次的频率刷新,由于刷新频率很高,因此你感觉不到它在刷新。而动画本质就是要让人眼看到图像被刷新而引起变化的视觉效果,这个变化要以连贯的、平滑的方式进行过渡。 那怎么样才能做到这种效果呢?
刷新频率为60Hz的屏幕每16.7ms刷新一次,我们在屏幕每次刷新前,将图像的位置向左移动一个像素,即1px。这样一来,屏幕每次刷出来的图像位置都比前一个要差1px,因此你会看到图像在移动;由于我们人眼的视觉停留效应,当前位置的图像停留在大脑的印象还没消失,紧接着图像又被移到了下一个位置,因此你才会看到图像在流畅的移动,这就是视觉效果上形成的动画。
setTimeout
和setInterval
理解了上面的概念以后,我们不难发现,setTimeout
其实就是通过设置一个间隔时间来不断的改变图像的位置,从而达到动画效果的。但我们会发现,利用seTimeout
实现的动画在某些配置较低的机器上会出现卡顿、抖动的现象。 这种现象的产生有两个原因:
-
setTimeout
的执行时间并不是确定的。在Javascript
中,setTimeout
任务被放进了异步队列中,只有当主线程上的任务执行完以后,才会去检查该队列里的任务是否需要开始执行,因此setTimeout
的实际执行时间一般要比其设定的时间晚一些。 -
刷新频率受屏幕分辨率和屏幕尺寸的影响,因此不同设备的屏幕刷新频率可能会不同,而
setTimeout
只能设置一个固定的时间间隔,这个时间不一定和屏幕的刷新时间相同。
以上两种情况都会导致setTimeout
的执行步调和屏幕的刷新步调不一致,从而引起丢帧现象。 那为什么步调不一致就会引起丢帧呢?
-
第0ms: 屏幕未刷新,等待中,
setTimeout
也未执行,等待中; -
第10ms: 屏幕未刷新,等待中,
setTimeout
开始执行并设置图像属性left=1px; -
第16.7ms: 屏幕开始刷新,屏幕上的图像向左移动了1px,
setTimeout
未执行