【JS动画】帧的理解与requestAnimationFrame的使用

一、帧的理解

1、帧

帧是影像或动画中的最小单位,相当于电影胶片上的每一格画面

2、帧数和帧率

  • 帧数:指一段时间内,产生的或者播放的帧的数量
  • 帧率:指一秒内产生的或者播放的帧的数量,单位为FPS,frames per second

二、requestAnimationFrame的使用

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。其通常执行回调函数的频率为每秒60次(约16.6ms刷新一次)。当然其刷新次数也与当下浏览器屏幕刷新次数相匹配。

1、执行刷新回调

通常,requestAnimationFrame与回调函数会构成循环嵌套,从而实现持续地帧刷新。

形如下:

function frame(){
    //下一帧的渲染逻辑:例如修改canvas图形的offset等、重新计算元素的transform属性值
    .....

    //停止下一次的帧刷新    
    if(终结判断 为真) return

    requestAnimationFrame(frame)
}

值得注意的是,当在class类中定义frame函数,并用将其作为回调函数时,一定要注意利用箭头函数解决this指向的问题 !直接requestAnimationFrame(this.frame)会使得this指向调用者window

正确写法如下:

class Renderer{
    ...
    frame(){


        //下一帧的渲染逻辑:例如修改canvas图形的offset等、重新计算元素的transform属性值
        .....

        //停止下一次的帧刷新    
        if(终结判断 为真) return

        requestAnimationFrame(()=>this.frame())

    }


}

 此时,利用箭头函数的特性【即this指向的是函数定义时,外部最近作用域中的this对象】,才可以准确调用frame函数

2、timestamp传参

该回调函数会传入 DOMHighResTimeStamp 参数,该参数与 performance.now() 的返回值相同,它表示 requestAnimationFrame() 开始执行回调函数的时刻。

*注意:若在同一帧时间内传入多个回调函数,每个回调函数中的timestamp值是相同的!

performance.now()与一些js中的time类(例如Date.now())不同的是,它不仅仅可以精确到一毫秒,而且可以以毫秒为单位作为浮点数返回,最大可精确到微秒级别

因此,当我们可以显示声明回调函数中的timestamp参数,从而准确计算这一帧中的物体状态。

例如:

const element = document.getElementById("some-element-you-want-to-animate");
let start, previousTimeStamp;
let done = false;

function step(timestamp) {
  if (start === undefined) {
    start = timestamp;
  }
  const elapsed = timestamp - start;

  if (previousTimeStamp !== timestamp) {
    // 这里使用 Math.min() 确保元素在恰好位于 200px 时停止运动
    const count = Math.min(0.1 * elapsed, 200);
    element.style.transform = `translateX(${count}px)`;
    if (count === 200) done = true;
  }

  if (elapsed < 2000) {
    // 2 秒之后停止动画
    previousTimeStamp = timestamp;
    if (!done) {
      window.requestAnimationFrame(step);
    }
  }
}

window.requestAnimationFrame(step);

3、取消动画帧的渲染

requestAnimationFrame的返回值是一个long类型的非0值,可理解为请求DI,作为回调列表中的唯一标识。

我们可以利用这个ID值,传入window.cancelAnimationFrame() 以取消相应的回调函数请求。

为提高性能和延长电池寿命,当浏览器将标签页切换至后台  或者 在隐藏的<iframe>里 时,requestAnimationFrame将会暂停调用执行。

三、为什么不用setInterval进行动画帧的刷新

setInterval属于定时器,即间隔一段时间后执行代码内容。

由于JS的执行是单线程的,其遵循事件循环(event loop)机制。而setInterval定时执行回调函数属于宏任务,这种执行顺序会导致其隐藏时间误差。

如果将setInterval作为帧刷新的控制器,其在长时间执行后,由于时间误差的累积,效果会越来越不理想!从而导致动画闪烁等情况

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

音仔小瓜皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值