在JS中,当事件触发很频繁,浏览器来不及处理时,就会导致页面出现卡顿的现象,解决这种卡顿问题,就需要用到了防抖和节流。

防抖和节流就是针对响应跟不上触发频率这类问题解决方案。

1、含义

防抖(debounce) 策略是,当事件被触发时,设定一个周期延迟执行动作,若期间又被触发,则重新设定周期,直到周期结束,执行动作。

节流(throttle) 策略是,在固定周期内,只执行一次动作,若有新事件触发,不执行,周期结束后,又有事件触发,开始新的周期。即:高频事件触发,但是在n秒内只会执行一次,会稀释函数的执行频率

2、实现原理:

防抖,维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置,这样一来,只有最后一次操作能被触发。

节流,通过判断是否到达一定时间来触发函数。有2种实现方式:时间戳和定时器,用时间戳实现的函数触发是在时间段内开始的时候,而定时器实现的函数触发是在时间段内结束的时候触发。

3、区别:

节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而防抖只是在最后一次事件后才触发一次函数。

4、使用场景:

用防抖:当程序只需要处理最后一次触发事件时。
比如:1)在输入框反复输入内容,输入结束后再执行操作;2)浏览器出口大小变化时,不需要计算中间的变化过程,只需要窗口大小改变完成后的值。

用节流: 当事件触发过于频繁,需要限制事件处理程序的调用频率时。
比如:1)滚动加载,如是否滑到底部自动加载更多;2)鼠标不断点击触发,mousedown(单位时间内只触发一次) ;3)高频点击提交,表单重复提交。

5、实现:
/**
 * @description: 防抖,触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
 * @param {Function} func 方法
 * @param {Number} delay 时间(单位:秒)
 * @return 无
 */
function debounce(func, delay) {
  let timer = null;
  return function () {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, arguments);
    }, delay);
  };
}

/**
 * @description: 节流,高频事件触发,但在n秒内只会执行一次
 * @param {Function} func 方法
 * @param {Number} delay 时间(单位:秒)
 * @return 无
 */
function throttle(func, delay) {
  let flag = true;
  return function () {
    if (!flag) {
      return;
    }
    flag = false;
    setTimeout(() => {
      func.apply(this, arguments);
      flag = true;
    }, delay);
  };
}

/**
 * @description: 节流(时间戳),高频事件触发,但在n秒内只会执行一次
 * @param {Function} func 方法
 * @param {Number} delay 时间(单位:秒)
 * @return 无
 */
function throttle2(func, delay) {
  let previous = 0;
  return function () {
    let now = Date.now();
    if (now - previous > delay) {
      func.apply(this, arguments);
      previous = Date.now();
    }
  };
}