跳到主要内容

认识

2024年03月06日
柏拉文
越努力,越幸运

一、认识


window.requestAnimationFrame() 底层是在一轮事件循环中浏览器绘制之前执行, 执行requestAnimationFrame 的回调。requestAnimationFrame 在浏览器决定渲染之前给你最后一个机会去改变 DOM 属性,然后很快在接下来的绘制中帮你呈现出来,所以这是做流畅动画的不二选择。由于 window.requestAnimationFrame() 执行时机在重绘之前, requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成, 减少了回流和重绘次数。

1.1 requestAnimationFrame vs 节流防抖

requestAnimationFrame 是浏览器提供的一个API,用于安排一个函数在浏览器下一次重绘之前执行。它的主要用途是用于动画和连续的绘制操作,比如页面滚动、元素拖动等。它能够让你的动画或绘制操作与浏览器的刷新率同步,从而减少重绘和回流,提高性能。相对于setInterval或连续的setTimeoutrequestAnimationFrame会在浏览器选项卡不是激活状态时自动停止,从而节省电力和处理器资源。requestAnimationFrame 自然地与浏览器的刷新率同步,所以在做动画等操作时,用户体验更加平滑自然。

节流防抖 主要用于限制函数执行的频率, 适用于对事件处理频率进行控制的情况,通过减少事件处理的次数来提高性能。

1.2 requestAnimationFrame vs setInterval

requestAnimationFrame 会尽可能地匹配显示器的刷新率,通常是60Hz,意味着它会努力每秒执行60次。这样可以保证动画的流畅度和减少掉帧的情况。相比之下,setInterval可能在不合适的时机执行动画帧,导致动画不流畅或浪费CPU资源。

当用户切换到其他标签页或者最小化浏览器时,requestAnimationFrame 会自动暂停,从而不会进行不必要的计算和渲染,节省了资源。而setInterval则会继续执行,即便用户可能根本看不到动画的执行,造成资源的浪费。

requestAnimationFrame 通过与浏览器的绘制过程同步,以确保动画的每一帧都能在屏幕刷新的最佳时机更新。这种同步可以减少或避免出现撕裂现象,提高动画和页面的渲染质量。setInterval则没有这种同步机制,可能会在屏幕绘制过程中的任意时刻更新界面,有时甚至导致多次绘制合并在一起显示。

requestAnimationFrame 提供的回调函数参数是DOMHighResTimeStamp(表示从页面加载开始到当前调用已经过去的时间),让用户可以更精确地控制动画的状态,根据已经过去的时间调整动画的进度。而setInterval需要自己计算和管理时间,为实现相同的效果增加了复杂性。

二、语法


const animationFrameID = window.requestAnimationFrame(callback);
  • callback: 下一次重绘之前更新动画帧所调用的函数 (即上面所说的回调函数)。该回调函数会被传入DOMHighResTimeStamp参数,该参数与performance.now()的返回值相同,它表示requestAnimationFrame()开始去执行回调函数的时刻

    • timestamp: 动画执行时长
  • animationFrameID: 一个 long 整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。你可以传这个值给 window.cancelAnimationFrame() 以取消回调函数。

三、问题


3.1 requestAnimationFrame 动画 Vs setInterval 动画 Vs setTimeout 动画

setInterval 动画、setTimeout 动画 : 会造成掉帧、卡顿、闪屏 的问题。原因是: setTimeout的执行时间并不是确定的。在JS中,setTimeout任务被放进事件队列中,只有主线程执行完才会去检查事件队列中的任务是否需要执行,因此setTimeout的实际执行时间可能会比其设定的时间晚一些。、刷新频率受屏幕分辨率和屏幕尺寸的影响,因此不同设备的刷新频率可能会不同,而setTimeout只能设置一个固定时间间隔,这个时间不一定和屏幕的刷新时间相同。 以上两种情况都会导致setTimeout的执行步调和屏幕的刷新步调不一致。在setTimeout中对dom进行操作,必须要等到屏幕下次绘制时才能更新到屏幕上,如果两者步调不一致,就可能导致中间某一帧的操作被跨越过去,而直接更新下一帧的元素,从而导致丢帧现象。

requestAnimationFrame动画: 与setTimeoutsetInterval相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机。换句话说就是,requestAnimationFrame 的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象。

参考资料


查看 setInterval 实现