防抖和节流函数的实现

防抖和节流函数的实现

首先我们需要对防抖和节流函数作一个概念的区别:因为这两者是不同的一个概念

一、防抖和节流函数的基本认识

  • 1.防抖函数
    防抖函数相当于是对触发的数据做一个延迟处理。比如我们平时在使用搜索框时,我们一输入内容就会发送对应的网络请求,如果我们后面一直有在输入内容,那么就会一直发送网络请求。正确的做法应该是在我们输入期间不发送网络请求,当我们输入完成后在发送网络请求。
  • 2.节流函数
    节流函数相当于是我们在一个时间段内一直频繁的触发数据请求,但是数据的请求还是根据设定的一个频率来进行响应的。比如我们在玩LOL游戏时,当需要回城时,我们触发回城按钮,进入到回城状态进会有一个等待的时间,如果在这个等待时间内有重复去执行回城按钮,这时回城状态并不会做出其他响应,而是等时间到了后才会完成回城。这也说明了,在我们回城的过程中,一直触发回城按钮都是不会响应的,他会按照自己的一个回城时间才做出响应。
  • 3.防抖函数和节流函数的区别
    区别:
    防抖函数,是将一段时间内频繁被执行的数据,延迟到后面一次性做一个执行
    节流函数,在触发了数据的请求后 ,当数据还没有响应时,在这段时间内无论重复执行多少次,都还是会执行设置数据响应的频率来执行的。也就是说设定的频率为10秒执行一次,那么无论在10内触发了多少次,过10秒后还是只会执行一次。

二、防抖函数的基本实现

代码如下(示例):

//创建一个防抖函数debounce
function debounce(fn, delay) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null

  // 2.真正执行的函数
  const _debounce = function () {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)
    // 延迟执行
    timer = setTimeout(() => {
      // 外部传入的真正要执行的函数
      fn()
    }, delay)
  }

  return _debounce
}

版本二:this和参数实现

//创建一个防抖函数debounce
function debounce(fn, delay) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null

  // 2.真正执行的函数
  const _debounce = function (...ages) {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)
      //因为这里是箭头函数,所以指向上层作用域,然后把参数给fn函数传递过去
      //因为参数可能不只一个所以使用展开语法。
      fn.apply(this, ages)
    }, delay)
  }

  return _debounce
}

版本三:立即执行

//创建一个防抖函数debounce
function debounce(fn, delay, immediate = false) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null
  let isInvoke = false
  // 2.真正执行的函数
  const _debounce = function (...ages) {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)

    // 判断是否需要立即执行
    if (immediate && !isInvoke) {
      fn.apply(this, ages)
      isInvoke = true
    } else {
      // 延迟执行
      timer = setTimeout(() => {
        // 外部传入的真正要执行的函数
        fn.apply(this, ages)
        isInvoke = false
      }, delay)
    }
  }

  return _debounce
}

版本四:取消功能

//创建一个防抖函数debounce
function debounce(fn, delay, immediate = false) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null
  let isInvoke = false
  // 2.真正执行的函数
  const _debounce = function (...ages) {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)

    // 判断是否需要立即执行
    if (immediate && !isInvoke) {
      fn.apply(this, ages)
      isInvoke = true
    } else {
      // 延迟执行
      timer = setTimeout(() => {
        // 外部传入的真正要执行的函数
        fn.apply(this, ages)
        isInvoke = false
      }, delay)
    }
  }

  //_debounce是一个函数,函数也可以做为是一个对象,所以我们可以给他添加方法
  _debounce.cancel = function () {
    //删除要执行的函数
    if (timer) clearTimeout(timer)
    //把所有属性都恢复成默认值
    timer = null
    isInvoke = false
  }

  return _debounce
}

版本五:函数的返回值

//创建一个防抖函数debounce
function debounce(fn, delay, immediate = false, resultCallback) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null
  let isInvoke = false
  // 2.真正执行的函数
  const _debounce = function (...ages) {
      // 取消上一次的定时器
      if (timer) clearTimeout(timer)

      // 判断是否需要立即执行
      if (immediate && !isInvoke) {
        const result = fn.apply(this, ages)
        isInvoke = true
        resultCallback(result)
      } else {
        // 延迟执行
        timer = setTimeout(() => {
          // 外部传入的真正要执行的函数
          const result = fn.apply(this, ages)
          resultCallback(result)
          isInvoke = false
        }, delay)
      }
  }

  //_debounce是一个函数,函数也可以做为是一个对象,所以我们可以给他添加方法
  _debounce.cancel = function () {
    if (timer) clearTimeout(timer)
    timer = null
    isInvoke = false
  }

  return _debounce
}

这里函数的返回值是通过传入的回调函数来实现,也可能通过返回一个Promise来完成

三、节流函数的基本实现

function throttle(fn, interval) {
  // 1.记录上一次的开始时间
  let lastTime = 0

  // 2.事件触发时, 真正执行的函数
  const _throttle = function () {
    // 2.1.获取当前事件触发时的时间
    const nowTime = new Date().getTime()

    // 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
    const remainTime = interval - (nowTime - lastTime)
    if (remainTime <= 0) {
      // 2.3.真正触发函数
      fn()
      // 2.4.保留上次触发的时间
      lastTime = nowTime
    }
  }

  return _throttle
}

版本二:leading 和trailing 的实现

function throttle(fn, interval, options = { leading: true, trailing: false }) {
  // 1.记录上一次的开始时间
  const { leading, trailing } = options
  let lastTime = 0
  let timer = null

  // 2.事件触发时, 真正执行的函数
  const _throttle = function (...args) {
    // 2.1.获取当前事件触发时的时间
    const nowTime = new Date().getTime()
    if (!lastTime && !leading) lastTime = nowTime

    // 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
    const remainTime = interval - (nowTime - lastTime)
    if (remainTime <= 0) {
      //进入到这我们肯定会调用函数的,所以需要防止重复调用
      if (timer) {
        clearTimeout(timer)
        timer = null
      }

      // 2.3.真正触发函数
      fn()

      // 2.4.保留上次触发的时间
      lastTime = nowTime
      return
    }

    //判断是否需要执行最后一次输出
    if (trailing && !timer) {
      timer = setTimeout(() => {
        timer = null
        //防止我们延迟调用函数时,上面时间到了后,又重复调用
        lastTime = !leading ? 0 : new Date().getTime()
        fn()
      }, remainTime)
    }
  }

  return _throttle
}

版本三this和参数实现

版本四取消功能

版本五函数的返回值

上面这三这个功能基本上是和节流函数中实现的没有差别,节流函数的重点就是leading和trailing的实现。所以重复的代码就不展示了。查看防抖函数上实现的功能即可。


总结

上述代码为防抖和节流函数的基本实现过程,和一些库里面的防抖节流函数差不多。但是想自己实现节流防抖函数的可以参数本文中的代码来实现一下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值