防抖动、节流阀与 rAF

3,844 阅读3分钟

1.简介

在 web 开发中,经常会对一些事件进行监听处理,从而达到我们需要的一些效果。但是某些事件触发特别频繁,如浏览器窗口的 resize 事件以及页面的滚动事件。如此频繁的事件监听以及处理函数的多次执行,势必会带来性能上不必要的损失和欠佳的用户体验。

因此,今天就初探一下类似问题的解决办法:防抖动(Debounce )、节流阀(Throttle)和 requestAnimationFrame。

2.防抖动(Debounce)

简单来说,防抖动技术就是把触发非常频繁的事件合并成一次执行。

先看一下代码实例:

function debounce(func, wait){
  var timeID = null;
  return function(){
    // 首先是清空定时器
    clearTimeout(timeID);
    // 延迟 wait ms后执行真正的事件处理函数
    timeID = setTimeOut(func, wait);
  }
}
function hanlder(){
  console.log('Hanlde the scroll event.');
}
window.addEventListener('scroll', debounce(hanlder, 400));

简要解释一下,如果在400ms内连续触发 scroll 事件,那么真正的事件处理是不会执行的。只有当快速的事件触发停止以后,处理函数才会执行,也就是说 debounce 函数将多次的事件触发合并成了一次。

3.节流阀(Throttle)

节流函数,只允许一个函数在规定的时间内执行一次。

它和防抖动最大的区别就是,节流函数是不管事件触发有多频繁,都会保证在规定事件内必须执行一次真正的事件处理函数。因此,有些场景下,就不能够使用防抖动技术,转而用节流阀代替。

比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流阀技术来实现。代码实例如下:

var throttle = function (func, wait){
  var timeout,
      context,
      args,
      startTime = Date.parse(new Date());
  
  return function(){
    var curTime = Date.parse(new Date());
    var remaining = wait - (curTime - startTime);
    context = this;
    args = arguments;
    
    clearTimeout(timeout);
    
    if(remaining <= 0){
      func.apply(context, args);
      startTime = Date.parse(new Date());
    }else{
      timeout = setTimeout(func, remaining);
    }
  }
};

4.requestAnimationFrame

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

如果你想做逐帧动画的时候,你应该用这个方法。这就要求你的动画函数执行会先于浏览器重绘动作。通常来说,被调用的频率是每秒60次,但是一般会遵循W3C标准规定的频率。如果是后台标签页面,重绘频率则会大大降低。

代码实例:

function update(timeStamp){
  // 执行动画一帧所需要的计算工作
  ...
}
requestAnimationFrame(update)

回调函数会被传入一个时间戳作为参数,该参数指示出回调函数将被触发的时间。

简单来说 rAF 会在浏览器渲染的下一帧执行动画所需的计算操作,而且执行的频率与显示器的刷新率保持一致,

这样就避免了我们使用定时器时由于指定的间隔时间太长或太短引起的动画掉帧或卡顿的问题。

浏览器兼容方面,IE 10.0及以上支持。

5.总结

第一次写博客,自我感觉对于技术的剖析很浅,没有达到自己理想的效果。慢慢来吧,再接再厉,参考文章列表里的都是一些非常优秀的文章,大家可以仔细阅读。

参考文章

  1. 【前端性能】高性能滚动 scroll 及页面渲染优化
  2. 实例解析防抖动(Debouncing)和节流阀(Throttling)
  3. Javascript高性能动画与页面渲染