requestAnimationFrame方法与动画
动画就是不间断地、基于时间的更新与重绘
所以一般有两种选择
动画类型
window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
当你准备更新动画时你应该调用此方法。这将使浏览器在下一次重绘之前调用你传入给该方法的动画函数(即你的回调函数)。回调函数执行次数通常是每秒60次,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在后台标签页或者隐藏的 里时,requestAnimationFrame() 会被暂停调用以提升性能和电池寿命。
回调函数会被传入 DOMHighResTimeStamp 参数,该参数指示当前被 requestAnimationFrame() 排序的回调函数被触发的时间。在同一个帧中的多个回调函数,它们每一个都会接受到一个相同的时间戳,即使在计算上一个回调函数的工作负载期间已经消耗了一些时间。该时间戳是一个十进制数,单位毫秒,最小精度为1ms(1000μs)。
// start 记录的是第一次调用step函数的时间点,用于计算与第一次调用step函数的时间差,以毫秒为单位
let start: number = 0;
// lastTime 记录的是上一次调用step函数的时间点,用于计算两帧之间的时间差,以毫秒为单位
let lastTime: number = 0;
// count用于记录step函数运行次数
let count: number =0;
/**
* step 函数用于计算:
* 1、获取当前时间点与HTML程序启动时的时间差: timestamp
* 2、 获取当前时间点与第一次调用step时的时间差: elapedMsec
* 3、 获取当前时间点与上一次调用step时的时间差: intervalMsec
* step函数是作为requestAnimationFrame方法的回调函数使用的
* 因此step函数的签名必须是(timestamp: number) => void
*
*/
function step (timestamp: number) : void {
// 第一次调用本函数时,设置start 和latsTime为timestamp;
if(!start) start = timestamp;
if(!lastTime) lastTime = timestamp
// 计算当前时间点与第一次调用step时间点的差
let elapsedMsec: number = timestamp - start;
// 计算当前时间点与上次调用step时间点的差(可以理解为两帧之间的时间差)
let intervalMsec: number = timestamp -lastTime;
// 记录上一次时间戳
lastTime = timestamp;
// 计数器,用于记录step函数被调用的次数
count ++ ;
console.log(" " + count + "timestamp = " + timestamp)
console.log(" " + count + "elapsedMsec = " + elapsedMsec)
console.log(" " + count + "intervalMsec= " + intervalMsec)
// 使用requestAnimationFrame调用step函数
window.requestAnimationFrame(step);
}
// 使用requestAnimationFrame启动step
// 而step函数中又会调用requestAnimationFrame来回调step函数
// 从而形成不间断地递归调用,驱动动画不停运行
window.requestAnimationFrame(step)
requestAnimationFrame与监视器刷新频率
通过requestAnimationFrame方法启动step回调函数后,每次调用step函数的时间间隔固定在16.66毫秒左右,基本上每秒调用60次step函数(1000 / 60约等于16.66毫秒,其中1秒等于1000毫秒)。每秒step函数调用的次数(频率)实际上是和监视器屏幕刷新次数(频率)保持一致
由此可见request Animation Frame是一个与硬件相关的方法,该方法会保持与监视器刷新频率一致的状态。
当我们在 step 中进行大量耗时操作结果会如何?
两帧之间的时间间隔(intervalMsec)总是16.66毫秒的倍数(当前监视器屏幕刷新频率60赫兹,折算成每帧需要16.66毫秒刷新一次)。
由此可见,requestAnimationFrame方法会稳定间隔时间:
● 如果当前的回调操作(step函数)在16.66毫米内能完成,那么requestAnimationFrame会等到16.66毫秒时继续下一次step回调函数的调用。
● 如果当前的回调操作(step函数)大于16.66毫秒,则会以16.66毫秒为倍数的时间间隔进行下一次step回调函数的调用。
● 当将监视器屏幕刷新频率60赫兹设置成48赫兹时,结果也类似,两帧之间间隔时间总是20.83毫秒的倍数
来源整理自:vue3js.cn 面试官系列



