[前端知识点]防抖和节流

[前端知识点]防抖和节流


基本概念

防抖和节流都是用来优化,防止时间触发频率过高导致的响应速度跟不上触发频率,出现延迟、假死或卡顿的现象

防抖(debounce):触发事件后一段时间内内函数只会执行一次,如果在这段时间事件再次被触发,则重新计算时间
节流(throttle):事件被触发,但在一段时间内只会执行一次,所以节流会稀释函数的执行频率

以滚动监听条为例,详细讲解一下防抖和节流

function showTop  () {
  let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll  = showTop

一、防抖

  • 实现:借用setTimeout函数设置延迟调用,每当用户再次调用则取消前一次调用
  • 缺点:事件如果不断被触发,调用方法也会迟迟不能出来
  • 应用场景:联想搜索、收藏点击、window触发resize等
function debounce(func, delay=100){
  // 初始化计时器
  let timer = 0
  return function (...args) {
    // 如果再次调用,则清除计时,重新调用
    if(timer) clearTimeout(timer)

    timer = setTimeout(() => {
      // 调用方法
      func.apply(this, args)
    }, delay)
  }
}

window.onscroll = debounce(showTop, 1000)

以上为基础的防抖,因为它通过异步函数最后执行,有一定延迟;一般的防抖会有immediate选项,表示是否立即调用

  • 延迟调用:搜索框input事件,支持输入实时搜索可以使用节流方案(间隔一段时间就必须查询相关内容----例如某度)。输入间隔大于某个值(如500ms),就当做用户输入完成,然后开始搜索
  • 立即执行:用户点收藏、star的时候,我们希望用户点第一下的时候就去调用方法,并且成功之后改变收藏、star按钮的样子,用户就可以立马得到反馈是否star成功了

因此,我们升级一下防抖函数:

function debounce(func, delay=100, immediate=true){
  let timer, context, args
  // 延迟执行函数
  const later = () => setTimeout(() => {
    // 延迟函数执行完毕,清空定时器
    timer = null
    if(!immediate){
      func.apply(context, args)
      context = args = null
    }
  }, delay)

  return function(...params){
    // 初次调用,创建later
    if(!timer){
      timer = later()
      // 如果立即执行
      if(immediate){
        func.apply(this, params)
      } else {
        context = this
        args = params
      }
    }
    // 如果再次调用,则清除计时,重新调用
    else{
      clearTimeout(timer)
      timer = later()
    }
  }
}

二、节流

  • 实现:一种是借用setTimeout函数,另一种是判断前后调用时间差,进阶版是将以上两种糅合在一起。每当用户触发事件,先判断函数是否已经调用,如果调用则直接截断退出
  • 应用场景:游戏功能(如王者荣耀技能按钮)、滚动条监听等
  1. 首先是时间戳基础版
function throttle(func, wait){
  // 初始化时间戳
  let context, args, prev = Date.now()
  
  return function (...parmas) {
    // 函数执行时间戳
    let _now = Date.now()
    // 如果时间差不足等待时间,则截断退出
    if(_now - prev < wait) return false
    // 时间差大于等待时间,函数可重新调用
    context = this
    args = parmas
    func.apply(context, args)
    prev = Date.now()  //更新上一次函数执行时间戳
  }
}
window.onscroll = throttle(showTop,1000)
  1. 接下来是setTimeout基础版
function throttle(func, delay){
  // 标记函数是否调用过
  let valid = true

  return function(...args){
  	// 函数正在执行,直接退出调用
    if(!valid) return false
    // 函数进入工作,不可再次执行
    valid = false
    setTimeout(() => {
      func.apply(this, args)
      valid = true  //执行完毕
    }, delay)
  }
}
window.onscroll = throttle(showTop,1000)

同样也是延迟的问题,游戏玩家点击技能,总不能让技能等一段时间才发出,因此我们需要加入immediate选项(暂未完成)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值