使用requestAnimationFrame相比setTimeout来进行防抖/节流,是否有优势?

4

我在MDN上看到了一个例子,它使用requestAnimationFrame而不是setTimeout

// Reference: http://www.html5rocks.com/en/tutorials/speed/animations/

var last_known_scroll_position = 0;
var ticking = false;

function doSomething(scroll_pos) {
  // do something with the scroll position
}

window.addEventListener('scroll', function(e) {
  last_known_scroll_position = window.scrollY;
  if (!ticking) {
    window.requestAnimationFrame(function() {
      doSomething(last_known_scroll_position);
      ticking = false;
    });
  }
  ticking = true;
});

这让我想到了我们是否可以使用requestAnimationFrame代替setTimeout(fn, 0),并且是否有任何优势?我已经谷歌搜索了一下,似乎所有比较都是在动画上下文中进行的,但是对于不相关的功能-如防抖节流或仅需要在重新绘制后运行代码的情况呢?


SetTimeout在必要的滴答上注册事件。因此,如果您有一个需要5个滴答的大任务,在它之前运行的函数将稍后执行。如果您每个滴答都有相同的函数运行,这可能会导致一些问题。requestAnimationFrame将跳过所有基于当前时间延迟的任务和进程。因此,在这种情况下,只有最后一个任务将运行。您可以查看以下文章:https://dev59.com/FWYr5IYBdhLWcg3wH23K - Rajesh
RequestAnimationFrame的优势在于它被设计为在您的监视器下一次绘制同步时触发。 换句话说,它旨在防止闪烁/撕裂。由于这一点,setTimeout在HTML5中的优势在于它可以每4毫秒触发一次,因此更快。但我认为最快的是Postmessage。 - Keith
3个回答

2

如果你想确保在两个帧更新之间更改了某些内容两次而不做不必要的工作,那么使用RequestAnimationFrame是很好的选择。

就本身而言,requestAnimationFrame除了动画以外没有其他用途,因为它只能等待16.666毫秒(如果没有延迟),因此需要将多个请求链接在一起。但如果与setTimeout配对使用,则可以等待特定数量的毫秒,并确保在正确的时间内绘制所有内容。


2

requestAnimationFrame被调用的时候,浏览器正在重新绘制页面。因此,理论上它应该避免在尝试将元素属性(如位置)与滚动位置同步时出现闪烁/抖动。

setTimeout将在至少n毫秒后调用,因此在下一次重新绘制之前,您的回调可能会被调用多次,从而浪费CPU使用率,或者多个连续的重新绘制发生而未调用回调,这将导致在尝试将元素属性与滚动位置同步时出现闪烁/抖动。


1
除了以上的答案, 当使用requestAnimationFrame时,动画只会在选项卡(或窗口)对用户可见时运行。这意味着CPU、GPU和内存使用较少,因此更加节能友好。这对于通常具有相对较短电池寿命的移动设备尤其重要。 但为了实现流畅的动画,我们必须确保我们的帧渲染在16ms以下完成,因此回调应该尽可能小,以便实现60 fps的动画效果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接