前端性能优化-防抖和节流

179 阅读1分钟

对于高频触发在前端来说是一直存在的问题,通常我们是采取了两种处理方式:debounce和throttling。

debounce 防抖

防抖策略是指当事件被触发时设定一个周期延迟执行动作,若期间又被触发则重新设定周期,直到周期结束再执行动作。
防抖又分两种:延迟debounce和前缘debounce

  • 延迟debounce: 在周期结束后再执行动作
  • 前缘debounce: 在触发时就执行动作

const debounce = (func, wait, immediate = false) => {
  let timer, timeStamp = 0;
  let context, args;

  const getNow = () => (new Date()).getTime();

  const run = (timerInterval) => {
    timer = setTimeout(() => {
      let now = getNow();
      let interval = now - timeStamp;

      if (interval < timerInterval) { // 还在周期时间内,便重置初始化事件并重新执行timeOut
        timeStamp = now;
        run(wait - interval)
      } else { // 周期已结束则触发执行函数,清除timeout
        if (!immediate) { // 延迟debounce 周期结束才执行
          func.apply(context, args)
        }
        clearTimeout(timer);
        timer = null
      }
    }, timerInterval);
  }

  return function() {
    context = this;
    args = arguments;
    let now = getNow()
    timeStamp = now
    if(!timer) {
      if (immediate) { // 前缘debounce 周期开始才执行
        fn.apply(context, args)
      }
      run(wait)
    }
  }
}

throttling 节流

节流策略是指在固定周期内,只执行一次动作,如果有新事件触发,则不执行。等下一个事件周期开始,如果有事件触发,才会执行下一次动作。 节流也分为两种:延迟throttling和前缘throttling

  • 前缘throttling: 触发时就执行动作,然后下一个周期开始时再触发下一次动作
  • 延迟throttling: 周期结束时再执行动作,然后下一个周期结束时再触发下一次动作
/**
 * func: 执行函数
 * wait: 防抖动时间间隔
 * immediate:false -> 延迟debounce  true -> 前缘debounce
 **/
const throttling = (func, wait, immediate) => {
  let timer, timeStamp = 0;
  let context, args;
  let run = () => {
    timer = setTimeout(() => {
      if (!immediate) {
        func.apply(context, args);
      }
      clearTimeout(timer); // 周期结束,清除计时器,重置null。以便下一次直接触发函数
      timer = null;
    }, wait);
  }

  return function() {
    context = this;
    args = arguments;
    if (!timer) { // 没有计时器则执行触发函数
      if (immediate) {
        func.apply(context, args)
      }
      run()
    }
    // 有计时器则不做任何操作
  }
}

防抖(debounce) 和 节流(throttling)