防抖和节流

1,108 阅读1分钟

防抖(debounce)

防抖的作用:把频繁触发的动作放在最后执行一次。常见的行为就是搜索引擎的搜索输入(百度是每次都触发,没有使用防抖),只在用户完成输入后进行匹配搜索。

实现思路:设置一个延迟的定时器,每次触发时,都取消之前的定时器并重新设置,达到最后执行一次的效果。

function debounce(fn,delay=500,immediate){
  let timer = null,immediateTimer = null;
  
  return function(){
      let args = arguments, context = this;
      
      // 第一次触发
      if(immediate && !immediateTimer){
      	fn.apply(context,args);
          //重置首次触发标识,否则下个周期执行时会受干扰
          immediateTimer = setTimeout(()=>{
          	immediateTimer = null;
          },delay);
      }
      // 存在多次执行时,重置动作需放在timer中执行;
      if(immediateTimer) clearTimeout(immediateTimer);
      if(timer) clearTimeout(timer);
      
      timer = setTimeout(()=>{
      	fn.apply(context,args);
          timer = null;
          immediateTimer = null;
      },delay);
  }
}

使用

let temp = debounce((e) => {
    console.log(this, e.target.value);
}, 500,true);
input.addEventListener('input', temp);

节流(throttle)

节流的作用:把频繁触发的动作按照一定周期执行。常见的行为就是滚动事件scroll,移动事件mousemove等。

实现思路:设置一个延迟的定时器,每次触发时,都重新设置定时器,达到最后执行一次的效果。

function throttle(fn, delay = 500, immediate = false) {
    let timer = null,
        immediateTimer = null,
        immediateRunning = !immediate;
    
    return function() {
        let context = this, args = arguments;

        if (immediate && !immediateRunning) {
          fn.apply(context, args);
          immediateRunning = true;
          // // 重置首次执行标识
          immediateTimer = setTimeout(()=>{
            immediateRunning = false;
          },delay);
          return;
        }

        if(!timer){
          // 如果有后续触发,在定时器中取消immediateTimer
          if(immediateTimer) {
              clearTimeout(immediateTimer);
              immediateTimer = null;
          };
          
          timer = setTimeout(() => {
            fn.apply(context, args);
            timer = null;
            immediateTimer = setTimeout(()=>{
              immediateRunning = false;
            },delay);
          }, delay)
        }
    }
  }

使用

let temp = throttle((e) => {
    console.log(this, e.target.value);
}, 500,true);
input.addEventListener('input', temp);