函数防抖与节流

2019/1/11 Javascript

# 防抖和节流

函数节流的核心是,让一个函数不要执行得太频繁,减少一些过快的调用来节流。

函数去抖就是对于一定时间段的连续的函数调用,只让其执行一次。

# 应用条件

发送一个 ajax 表单,给一个 button 绑定 click 事件,并且监听触发 ajax 请求。如果是 debounce,则用户不管点多少次,都只会发送一次请求;如果是 throttle,不断点击的过程中会间隔发送请求。这时候最好使用 debounce. 监听滚动事件判断是否到页面底部自动加载更多,如果是 debounce,则只有在用户停止滚动的时候的才会判断是否到了底部,如果是 throttle,则页面滚动的过程中会间隔判断是否到达底部。 此时最好使用 throttle

# 函数防抖

/**
 * 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
 *
 * @param  {function} func        回调函数
 * @param  {number}   wait        表示时间窗口的间隔
 * @param  {boolean}  immediate   设置为ture时,是否立即调用函数
 * @return {function}             返回客户调用函数
 */
const debounce = (func, wait = 1000, immediate = true) => {
  let timer;
  let context;
  let args;

  // 延迟执行函数
  const later = () =>
    setTimeout(() => {
      // 延迟函数执行完毕,清空缓存的定时器序号
      timer = null;
      // 延迟执行的情况下,函数会在延迟函数中执行
      // 使用到之前缓存的参数和上下文
      if (!immediate) {
        func.apply(context, args);
        context = null;
        args = null;
      }
    }, wait);

  // 这里返回的函数是每次实际调用的函数
  return (...params) => {
    // 如果没有创建延迟执行函数(later),就创建一个
    if (!timer) {
      timer = later();
      // 如果是立即执行,调用函数
      // 否则缓存参数和调用上下文
      if (immediate) {
        func.apply(this, params);
      } else {
        context = this;
        args = params;
      }
      // 如果已有延迟执行函数(later),调用的时候清除原来的并重新设定一个
      // 这样做延迟函数会重新计时
    } else {
      clearTimeout(timer);
      timer = later();
    }
  };
};

export default debounce;

# 函数节流

const throttle = (func, delay) => {
  let last;
  let deferTimer;
  return (...args) => {
    const now = +new Date();
    if (last && now < last + delay) {
      clearTimeout(deferTimer);
      deferTimer = setTimeout(() => {
        last = now;
        func.apply(this, args);
      }, delay);
    } else {
      last = now;
      func.apply(this, args);
    }
  };
};

export default throttle;