在防抖函数中使用requestAnimationFrame是否是个好主意?

10

这是我对requestAnimationFrame的理解验证。因为我需要一个防抖函数,每次窗口大小改变都会进行一些DOM交互,我不想让浏览器负担过重。典型的防抖函数每个时间间隔只会调用传递的函数一次,时间间隔通常是第二个参数。我假设对于大多数UI工作,最佳间隔时间是不会使浏览器超载的最短时间。在我看来,这正是requestAnimationFrame所能实现的:

var debounce = function (func, execAsap) {
   var timeout;

  return function debounced () {
    var obj = this, args = arguments;
    function delayed () {
      if (!execAsap)
        func.apply(obj, args);
      timeout = null; 
    };

    if (timeout)
      cancelAnimationFrame(timeout);
    else if (execAsap)
      func.apply(obj, args);

    timeout = requestAnimationFrame(delayed); 
  };
}

上面的代码直接复制自上面的debounce链接,但使用了请求动画帧代替setTimeout。据我理解,这将尽快地将传入的函数排队,但浏览器无法处理的任何调用都会被丢弃。这应该产生最平滑的交互效果。我是在正确的轨道上吗?还是我误解了requestAnimationFrame
(当然,这仅适用于现代浏览器,但有一些简单的requestAnimationFrame Polyfill可回退到setTimeout。)

1
如果涉及到重绘,并且您想要平滑的动画效果,您需要使用“节流”而不是“去抖动”。请重新阅读您链接的博客文章,了解它们之间的区别-去抖动不是“每个间隔调用一次传递的函数”。 - Bergi
1
@Bergi 感谢您的回复。我第一次阅读时考虑过这个问题,但我重新审视了它,并仔细阅读了Ben Alman在http://benalman.com/projects/jquery-throttle-debounce-plugin/上对两者差异的说明,我认为你可能是正确的。不过,我认为使用快速响应的浏览器可以最小化这两者之间的差异。 - carpeliam
想的和你一样。很高兴我找到了这篇文章。最好添加一个上下文参数来代替 var obj = this。这样人们在调用之前就不必使用 bind,并且可以节省创建另一个函数作用域的时间。 - Dogoku
1个回答

2

这将起作用。

但是有一个注意事项,可能对你很重要,也可能不重要:

如果页面当前不可见,则该页面上的动画可能会受到严格的限制,以使它们不经常更新,从而消耗很少的CPU功率。

因此,如果你对于需要去抖动的函数非常在意这一点,最好使用setTimeout(fn, 0)

否则,如果你正在使用它来进行动画,那么这就是requestAnimationFrame被设计来使用的方式


这对我的特定情况非常有意义 - 我正在resize事件上进行一些DOM交互,如果我的选项卡不活动,我可以接受在用户切换回我的选项卡之前不进行该交互。 - carpeliam

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