loading

requestAnimationFrame

# 什么是 requestAnimationFrame

顾名思义,请求动画帧,也称 帧循环

# 怎么用

window.requestAnimationFrame()

  • 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
function test() {
    console.log('🚀🚀hello ~ requestAnimationFrame');
  }
  requestAnimationFrame(test)
1
2
3
4

# 怎么做动画

注意:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用window.requestAnimationFrame()
1

说人话:递归调用自己

let n = 0
  function test() {
    n++
    console.log(`🚀🚀hello ~ requestAnimationFrame ${n}`);
    requestAnimationFrame(test)
  }
  requestAnimationFrame(test)
1
2
3
4
5
6
7

# 执行频率

回调函数执行次数通常是每秒 60 次,但在大多数遵循 W3C 建议的浏览器中,回调函数执行次数通常与 浏览器屏幕刷新次数 相匹配。

屏幕刷新频率(次数): 屏幕每秒出现图像的次数。普通笔记本为60Hz。

# 回调参数(执行时间)

回调函数会被传入DOMHighResTimeStamp参数,DOMHighResTimeStamp指示当前被 requestAnimationFrame() 排序的回调函数被触发的时间。

function test(timestamp) {
    console.log(`🚀🚀hello ~ requestAnimationFrame ${timestamp}`);
    requestAnimationFrame(test)
  }
  requestAnimationFrame(test)
1
2
3
4
5

此时间精确到三位小数

注意:

在同一个帧中的 多个回调函数 ,它们每一个都会接受到一个 相同的时间戳 ,即使在计算上一个回调函数的工作负载期间已经 消耗了一些时间 。该时间戳是一个十进制数,单位毫秒,最小精度为1ms(1000μs)。

就是浏览器刷新一次的时候,执行所有的 requestAnimationFrame ,并且它们的回调参数是一模一样的。

# 浏览器对它的优化

为了提高性能和电池寿命,因此在大多数浏览器里,当requestAnimationFrame() 运行在后台标签页或者隐藏的

说人话:不在当前页面,不执行 requestAnimationFrame,回来后再执行

# 返回值

一个 long 整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。

你可以传这个值给 window.cancelAnimationFrame() 以取消回调函数。

const beginBtn = document.querySelector("#begin")

  const endBtn = document.querySelector("#end")

  let myRef;

  beginBtn.addEventListener("click", () => {
    myRef = requestAnimationFrame(test)
  })

  endBtn.addEventListener("click", () => {
    cancelAnimationFrame(myRef)
  })

  function test() {
    myRef = requestAnimationFrame(test)
    console.log('🚀🚀~ myRef:', myRef);
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

也可以设置条件来终止

 function test(timestamp) {
    console.log(`🚀🚀hello ~ requestAnimationFrame ${timestamp}`);
    if (timestamp < 500) {
      requestAnimationFrame(test)
    }
  }
  requestAnimationFrame(test)
1
2
3
4
5
6
7

# setTimeout && setInterval

setTimeout 和 setInterval 的问题是,它们不够精确。它们的内在运行机制决定了 时间间隔参数 实际上只是指定了把动画代码添加到 浏览器UI线程队列 中以等待执行的时间。如果队列前面已经加入了其它任务,那动画代码就要等前面的 任务完成后 再执行,并且如果时间间隔过短(小于16.7ms)会造成丢帧,所以就会导致动画可能不会按照预设的去执行,降低用户体验。 requestAnimationFrame 采用 浏览器时间间隔 ,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,消耗性能;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个 统一 的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。

# CSS3动画

CSS3 的transition 和 animation 搭配使用可以说是非常强大了,但是也有做不到的地方,比如说 scrollTop,另外 CSS3 动画支持的贝塞尔曲线也是有限的。CSS3 做不到的就可以用到 requestAnimationFrame 来解决了

# 缺点

一般来说,requestAnimationFrame 执行都是很稳定的,但是当浏览器渲染线程被过度占用时这个API调用间隔会非常不稳定,它并不是银弹。

最近更新时间: 2021/08/25 17:25:09
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00