JS 节流 防抖

防抖:在任务高频率触发时,只有触发间隔超过制定间隔的任务才会执行。即一个动作连续触发则只执行最后一次。防抖的原理则是不管你在一段时间内如何不停的触发事件,只要设置了防抖,则只在触发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)
})



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

函数防抖的应用场景

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

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小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)
    }
  }

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

效果见:jsbin.com/hufazicemu/ed

节流:假设近期我们有发放口罩 的爱心机制——每天早上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)
        }
    }
}

效果:jsbin.com/vevamuwusa/ed

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

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

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

效果见:jsbin.com/yuruzoravi/1/

本文参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值