Debounce,Throttle概念及应用

前言

在页面上监听诸如scroll(页面滚动),mousemove(鼠标移动) ,keydownkeyupkeypress(按下键盘)等等一系列事件的时候,我们并不希望频繁的触发这类监听,尤其当请求非常消耗资源时,这种操作会导致服务器性能急剧下降。

比如EduSoho中选择课程老师的功能,只要输入字符就能显示出匹配的所有用户名。简单的keyup事件,可能会导致每输入一个字符,就触发一次请求,当输入【王老师】的时候整整发送了10个AJAX请求。如下图所示:
Debounce,Throttle概念及应用_第1张图片
我们需要降低这种无效的请求。这时,debounce 和 throttle 就派上用场了。

Debounce

DOM 事件里的 debounce 概念其实是从机械开关和继电器的去弹跳(debounce)衍生出来的,基本思路就是把多个信号合并为一个信号。

在Java中,Debounce函数所做的事情就是,强制一个函数在某个连续时间段内只执行一次,哪怕它本来会被调用多次。我们希望在用户停止某个操作一段时间之后才执行相应的监听函数,而不是在用户操作的过程当中,浏览器触发多少次事件,就执行多少次监听函数。

比如,在某个3s的时间段内连续地移动了鼠标,浏览器可能会触发几十(甚至几百)个mousemove事件,不使用Debounce的话,监听函数就要执行这么多次;如果对监听函数使用 100ms的去弹跳,那么浏览器只会执行一次这个监听函数,而且是在第 3.1s 的时候执行的。

现在,我们来实现一个Debounce 函数

/**
 * @param func {Function} 要执行的函数
 * @param delay {Number} 延迟时间,单位是毫秒(ms)
 * @return {Function} 返回一个`去弹跳`了的函数
 */
 function debounce(func, delay) {
   let timer;

   return function() {
     let self = this;
     let args = arguments;
     
     // 每次这个返回的函数被调用,就清除定时器,以保证不执行 func
     clearTimeout(timer);
     
     timer = setTimeout(function() {
       func.apply(self, args);
     }, delay);
   }
 }

页面滚动到元素可见位置的例子

function scrollHandler() {
  let winPos = $(window).scrollTop();
  let elementHeight = $('.element').offset().top - $(window).height();
 
  if (winPos >= initCounterHeight) {
    console.log('scroll');
  }
}

$(window).scroll(debounce(scrollHandler, 100));

Throttle

Throttle 的概念理解起来更容易,就是固定函数执行的速率,即所谓的节流。正常情况下,mousemove 的监听函数可能会每 20ms(假设)执行一次,如果设置200ms的节流,那么它就会每200ms执行一次。比如在 1s的时间段内,正常的监听函数可能会执行50(1000/20)次,节流 200ms后则会执行5(1000/200)次。

/**
 * @param func {Function} 要执行的函数
 * @param delay {Number} 执行间隔,单位毫秒
 * @return {Function} 返回一个`节流`的函数
 */
function throttle(func, delay) {
  let startTime = 0;
  return function() {
    let currentTime = + new Date();
    
    if (currentTime - startTime > delay) {
      func.apply(this, arguments);
      startTime = currentTime;
    }
  }
} 

改变窗口大小的例子

function resizeHandler() {
  console.log('resize');
}

window.onresize = throttle(resizeHandler, 300);

总结

Debounce其实就是把触发非常频繁的事件合并成一次延迟执行,合理使用可以减少服务器压力,加快浏览器的渲染速度。

Throttle设置一个阀值,在阀值内,把触发的事件合并成一次执行;当到达阀值,必定执行一次事件。

可以访问这个demo来查看Debounce、Throttle和默认情况的事件监听效果。

Demo网址:http://demo.nimius.net/debounce_throttle/

上一篇 Mysql 慢查询日志 分析篇

下一篇利用Jmeter进行分布式的性能测试

EduSoho官网 https://www.edusoho.com/
EduSoho开源地址 https://github.com/edusoho/edusoho
我们正在寻找开发者

你可能感兴趣的:(Javascript,EduSoho)