防抖:在任务高频率触发时,只有触发间隔超过制定间隔的任务才会执行。即一个动作连续触发则只执行最后一次。防抖的原理则是不管你在一段时间内如何不停的触发事件,只要设置了防抖,则只在触发n秒后才执行。如果我们在一个事件触发的n秒内又触发了相同的事件,那我们便以新的事件时间为标准,n秒之后再执行。



let timer = flase;
document.addEventListener('scroll', function() {
  clearTimeout(timer); // 清除未执行的定时器(如果之前已经触发过不到300毫秒又触发了一次则清除之前的)重置回初始化状态
  timer = setTimeout(function(){
    console.log("函数防抖")
  }, 300)
})



节流:在制定间隔内任务只执行1次。节流的原理是不管你在一段时间内如何不停地触发事件,只要设置了节流,就会每隔一段时间执行一次。



let canRun = true;
document.addEventListener('scroll', function() {
  if (!canRun) return;
  canRun = false;
  setTimeout(function(){
    console.log('函数节流')
    canRun = true
  }, 300)
})



两者区别:一定时间内任务执行的次数。防抖是只执行重复操作的最后一次,而节流是每多少单位时间内只执行一次。一个在线体验防抖和节流的效果的网站:http://demo.nimius.net/debounce_throttle/



jquery的防抖节流函数 js防抖节流原理_jquery的防抖节流函数

jquery的防抖节流函数 js防抖节流原理_javascript_02

函数防抖的应用场景

连续的事件,只需触发一次回调的场景有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

函数节流的应用场景

间隔一段时间执行一次回调的场景有:

  • 滚动加载,加载更多或滚到底部监听
  • 谷歌搜索框,搜索联想功能
  • 高频点击提交,表单重复提交


形象记忆

防抖:假设电梯的安全机制为每人进门后1分钟(wait)后才有关门动作,你第一个进电梯,快50秒的时候进来一位乘客(触发deBounce),得,刚才的50秒白等啦(clearTimeout),两人得一起重来再等新的1分钟。刚过又30秒,上来另一位乘客(再次触发deBounce),关门指令定时器又作废了(clearTimeout),大家得重新等新的1分钟,这1分钟内没人进来(触发deBounce)的话,那1分钟后关门动作就会执行了。

封装防抖函数:



function deBounce(fn, wait) {
    var timer
    return function() {
      if(timer) { clearTimeout(timer) }
      timer = setTimeout(() => {
        fn.apply(this, arguments)
      }, wait)
    }
  }



要点:如果在定时器的时间范围内再次触发,则重新计时。

效果见:https://jsbin.com/hufazicemu/edit?html,console,output



jquery的防抖节流函数 js防抖节流原理_搜索_03



jquery的防抖节流函数 js防抖节流原理_jquery的防抖节流函数_04

节流:假设近期我们有发放口罩 的爱心机制——每天早上8点发一个,必须一天后口罩寿命到了戴完用掉了才能再来领新的。24h内(wait)没用完丢弃前,你来领口罩(触发throttle)是不能给你发放的,你反复几次来领都没用,看到你口罩还能用(timer为真)就劝退(不执行if语句)。等24h时间到了后(setTimeout宏任务执行)口罩戴完了扔掉了(timer = null),看到你脸上没口罩可用了(timer为假),就才执行发放口罩动作(if语句内动作)。

封装节流函数:



function throttle(fn, wait) {
    var timer
    return function() {
        if (!timer) {
            timer = setTimeout(() => {
                timer = null
                fn.apply(this, arguments)
            }, wait)
        }
    }
}



效果:https://jsbin.com/vevamuwusa/edit?html,console,output



jquery的防抖节流函数 js防抖节流原理_html_05



jquery的防抖节流函数 js防抖节流原理_搜索_06

另一种写法(原理相同):



function throttle(fn, interval) {
  let canRun = true
  return function(){
    if(!canRun) {
      return
    }
    canRun = false
    setTimeout(()=>{
      fn.apply(this, arguments)
      canRun = true
    }, interval)
  }
}



要点:如果在定时器的时间范围内再次触发,则不予理睬,等当前定时器完成,才能启动下一个定时器。

效果见:https://jsbin.com/yuruzoravi/1/edit?html,console,output