节流和防抖

·  阅读 348

防抖和节流属于性能优化,在进行窗口的resize、滚动条scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。

此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。

函数防抖(debounce)

不管事件触发频率多高,一定在事件触发n秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,就以新的事件的时间为准,n秒后才执行。对于短时间内连续触发的事件,防抖的含义就是让某个时间期限(如上面的1000毫秒)内,事件处理函数只执行一次。

实现:

  • 实现的关键就在于setTimeout这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。
  • 里面的setTimeout则用的箭头函数,这样做的意义是让this的指向准确,this的真实指向并非debounce的调用者,而是返回闭包的调用者。
  • 对传入闭包的参数进行透传
 function debounce(event, time) {
    let timer = null;
    return function(...args) {
      clearTimeout(timer);
      timer = setTimeout(()=> {
        event.apply(this, args);
      }, time)
    }
 }
 // 如果需要立即执行, 加一个flag 标志, 定时器变量`timer`为空时,说明是第一次执行,我们立即执行它。
 
 function debounce(fn, time, flag) {
   let timer = null;
   return function(...args) {
    clearTimeout(timer);
    if(flag && !timer) {
       fn.apply(this, args)
    }
    timer = setTimeout(()=> {
       fn.apply(this, args);
    }, time)
   }
 }

复制代码

应用场景:

1、窗口的resize

window.addEventListener('resize', debounce(handleResize, 200))
复制代码

2、滚动条scroll

function showTop() {
  const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log(scrolltop);
}
window.addEventListener('scroll', debounce(showTop, 1000))
复制代码

3、输入框内容校验, 搜索框

debounce(valicator/fetchSelectData, 1000)
复制代码

函数节流(throttle)

当持续触发事件时,保证一定时间段内只调用一次事件处理函数.

节流好比水龙头放水,按照一定规律在某个时间间隔内一滴一滴的往下滴, 不开阀放水浪费;

函数节流主要有两种实现方法: 时间戳和定时器;

时间戳实现:

首刻发生,尾刻不发生,中间正常

function throttle(event, time) {
    let pre = 0;
    return function(...args) {
       if(Date.now() - pre > time) {
          pre = Date.now();
          event.apply(this, args);
       }
    } 
}

复制代码

定时器实现

首刻不发生,尾刻发生,中间正常;

function throttle(event, time) {
  let timer = null;
  return function(...args) {
    if(!timer) {
       timer = setTimeout(()=>{
         clearTimeout(timer)
         timer=null;
         event.apply(this, args);
       }, time);
    }
  }
}
复制代码

结合

function throttle(event, time) {
  let pre = 0, timer = null;
  return function(...args) {
     if(Date.now() - pre > time) {
         pre= Date.now();
         timer = null
         clearTimeout(timer);
         event.apply(this, args)
     } else if(!timer) {
        timer = setTimeout(()=>{
          event.apply(this, args);
        }, time);
     }
  }
}
复制代码
分类:
前端
收藏成功!
已添加到「」, 点击更改