函数的节流与防抖

之前项目中有遇到过这样一个问题,项目中需要监听一个滚动事件然后触发相应的操作,但是滚动操作是一个高频操作,而且触发的边界条件并不能严格控制触发的频率,所以会造成事件被高频词的触发,会造成页面的卡顿等问题。然后研究了一下解决方案,发现有两个概念,节流与防抖。

函数的节流与防抖主要的作用都是用来限制一个方法被频繁的调用,以达到优化性能的目的。

debounce (函数防抖)

会在第一次调用函数之后(不会立即执行函数)创建一个定时器,在指定时间之后再运行该函数。如果在函数运行之前再次调用,那么定时器会被重置。

实现代码:

/**
 * 防抖
 * @param {function} fn
 * @param {number} delay
 */
function debounce(fn, delay) {
  let timer;
  return function() {
    if (timer) clearTimeout(timer);
    let _this = this;
    let args = arguments;
    timer = setTimeout(() => {
      fn.apply(_this, args);
    }, delay)
  };
}

使用样例:

function logTime() {
  console.log(new Date());
}

window.onscroll = debounce(logTime, 600);

以上样例代码是在页面滚动时添加的防抖函数,只有在用户停止滚动之后600ms之后才会执行logTime动作。在滚动过程中是不会执行动作的。

throttle (函数节流)

实现代码:

/**
 * 节流
 * @param {function} fn
 * @param {number} intervalTime
 */
function throttle(fn, intervalTime) {
  let flagTime = 0;
  return function() {
    let nowTime = Date.now();
    if (nowTime - flagTime > intervalTime) {
      fn();
      flagTime = Date.now();
    }
  };
}

使用样例:

const logTime = () => {
  console.log(new Date());
}

window.onscroll = throttle(logTime, 1000);

以上样例代码在页面滚动时会每隔1s打印一次时间。

总结

防抖会把高频的函数调用转化成最后一次函数调用间隔时间后执行,列如电梯上人只有最后一个人上了没人再上来,电梯等一会再关门出发,如果一直上人(。。。不可能一直上)那么电梯永远不会出发(这里的电梯指的是带门的那种,不是商场的扶梯(()。可以用在页面滚动触发事件的操作上,或者input输入之后ajax发请求验证。

节流就是把高频高作转化成一定频次的间隔执行,控制函数的调用频率。可以用在需要实时计算的一些操作上,比如鼠标拖拽操作时计算位置等。

lodash debounce 源码

lodash throttle 源码