debounce/throttle 使用 requestAnimationFrame 而不是 setTimeout 有什么好处吗

Is there any advantage to using requestAnimationFrame instead of setTimeout for debounce/throttle

我在 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),这是否有任何优势?我用谷歌搜索了一下,似乎所有的比较都是在动画的上下文中完成的,但是不相关的功能呢 - 比如 debounce/throttle 或者只是如果你需要 运行 重绘后的代码?

RequestAnimationFrame 如果您想确保不做不必要的工作,因为您在 2 帧更新之间更改了两次内容,那是个不错的选择。

就其本身而言,requestAnimationFrame 除了动画之外没有任何用处,因为它只能等待 16.666 毫秒(如果没有延迟),因此您需要将多个链接在一起。但是如果你将它与 setTimeout 配对,那么你将能够等待特定的毫秒数,并确保你在正确的时间绘制所有内容。

requestAnimationFrame 在浏览器处于重绘步骤时被调用。因此理论上,如果您尝试将元素的属性(如位置)与滚动位置同步,它应该避免 flickering/jittering。

setTimeout 将在至少 n 毫秒后被调用,因此您的回调可能会在下一次重绘之前被多次调用,并且您将浪费 CPU 用法,或者连续多次重绘会在没有调用回调的情况下发生,如果您尝试将元素的属性与滚动位置同步,这将导致 flickering/jittering。

除了以上答案,

当使用 requestAnimationFrame 时,您的动画将仅在选项卡(或 window)对用户可见时 运行 显示。这意味着更少 CPU、GPU 和内存使用,因此电池友好。这对于电池寿命通常相对较短的移动设备尤其重要。

但为了流畅的动画,我们必须注意我们的帧渲染发生在 16 毫秒以内,因此对于 60 fps 的动画,回调应该尽可能小。