优化JS动画之requestAnimationFrame

本文详细介绍了requestAnimationFrame的工作原理及其相对于setInterval和setTimeout的优势。通过利用显示器的刷新机制,requestAnimationFrame能够更高效地执行动画效果,同时减少CPU和GPU的负担。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

优化动画之requestAnimationFrame

什么事requestAnimationFrame

  requestAnimationFrame(请求动画帧)是浏览器的全局对象window下的一个方法,其作用是用来实现页面中的某些动画效果.在MDN上的描述是:

window.requestAnimationFrame() 方法告诉浏览器您希望执行动画,并请求浏览器调用指定的函数在下一次重绘之前更新动画。该方法将在重绘之前调用的回调作为参数。

为什么要使用requestAnimationFrame

  或许有人会疑问,用JS执行页面动画效果不是有setIntervalsetTimeout了吗,那为什么还要使用requestAnimationFrame,
它有着什么样的好处.

  很多人都知道,由于JS的单线程特性以及使用事件队列的运行机制使得在使用setintervalsetTimeout方法来实现的JS动画其效果往往差强人意.

  这是因为单线程的JS在每一个时间段内只能执行一个任务,如遇到多个任务同时触发,也会先只执行一个.将剩余的放入事件队列当中.等到当前任务执行完了之后,在从队列中取出下一个任务进行执行,并在执行完成之后,再取出下一个任务.如此往复,直至事件队列的任务都执行完毕.这样就导致了JS在事件队列的任务执行完之前,会造成阻塞,在这期间JS是不会区执行其他的任务请求,包括setintervalsetTimeout这两个定时器的触发.由此就导致了setintervalsetTimeout的触发执行时间无法把控,从而造成页面上的JS动画效果不理想.

请看下面代码:

setTimeout(function(){
  console.log(1);
},0)

console.log(2);

// 2
// 1

  在上面这段代码中我们首先设定了一个定时器,并指定它在0毫秒之后触发,console.log打印出1,之后又在定时器的下面写了一个console.log打印出2.就上面的代码来看,不考虑其它的执行因素,它的结果应该是先打印出1,在打印出2.因为0毫秒就是相当于立即触发,不会等待.而事实上,在JS的运行环境中的结果是先打印出2,再打印出1.所以这段代码的实际运行过程是:
  先定义一个定时器,但不去管它的触发时间.因为当前的任务要求只是要设定一个定时器.然后执行下一个任务.console.log打印2.之后将当前队列中的任务执行完毕后,再去检查定时是否到达了指定的触发时间.如果达到则执行定时器中的代码由此console.log打印出1

  以上就是一个定时器的大概执行过程,在这个过程中JS永远只会在当前的事件队列里的人物执行完毕后才会去检查定时是否到达指定的触发时间.哪怕在这期间的耗时超过了定时器的指定触发时间,也不会例外.所以这就是为什么很多使用setintervalsetTimeout做的JS动画效果越往后会感觉越卡的原因所在了.而由此针对这个问题就诞生了requestAnimationFrame这个专门的JS动画API.

requestAnimationFrame的优势

  requestAnimationFrame的优势,在于充分利用显示器的刷新机制,比较节省系统资源。显示器有固定的刷新频率(60Hz或75Hz),也就是说,每秒最多只能重绘60次或75次,requestAnimationFrame的基本思想就是与这个刷新频率保持同步,利用这个刷新频率进行页面重绘。此外,使用这个API,一旦页面不处于浏览器的当前标签,就会自动停止刷新。这就节省了CPU、GPU和电力。
  不过有一点需要注意,requestAnimationFrame是在主线程上完成。这意味着,如果主线程非常繁忙,requestAnimationFrame的动画效果会大打折扣。

requestAnimationFrame的语法

&esmp;&esmp;requestAnimationFrame的语法的语法很简单:

requestID = window.requestAnimationFrame(callback);

只需要window对象调用requestAnimationFrame方法.并传入一个回调函数即可.跟setintervalsetTimeout不同它无需指定动画的间隔时间.因为它的间隔时间就是显示器的刷新频率.同时,调用了requestAnimationFrame后将会返回一个长整型非零值,作为一个唯一的标识符.你可以将该值作为参数传给window.cancelAnimationFrame()来取消这个回调函数.

下面是由MDN上给出的一个例子


window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;

var start = null;
var d = document.getElementById('SomeElementYouWantToAnimate');
function step(timestamp) { 
  if (start === null) start = timestamp;
  var progress = timestamp - start;
  d.style.left = Math.min(progress/10, 200) + "px";
  if (progress < 2000) {
    requestAnimationFrame(step);
  }
}
requestAnimationFrame(step);

requestAnimationFrame的兼容性

requestAnimationFrame的兼容性

参考资料 :

  1. MDN - window.requestAnimationFrame

  2. JavaScript 标准参考教材 - requestAnimationFrame

我的个人网址 https://wangyiming.info/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值