防抖与节流(详解)

防抖

我们可以通过一幅图来认识这个过程
在这里插入图片描述

  • 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间;
  • 当事件密集触发时,函数的触发会被频繁的推迟;
  • 只有等待了一段时间也没有事件触发,才会真正的执行响应函数;

应用场景

  • 搜索框输入数据,触发事件
  • 频繁的点击按钮
  • 监听屏幕滚动事件
  • 用户窗口的resize事件

防抖的意义:只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数;

undercore实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

<button>按钮</button>

<input type="text">

<!-- CDN引入: 网络的js文件 -->
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.4/underscore-umd-min.js"></script>
<!-- 本地引入: 下载js文件, 并且本地引入 -->
<!-- <script src="./js/underscore.js"></script> -->
<script>
    // 1.获取input元素
    const inputEl = document.querySelector("input")

    // 2.监听input元素的输入
    // let counter = 1
    // inputEl.oninput = function() {
    //   console.log(`发送网络请求${counter++}:`, this.value)
    // }

    // 3.防抖处理代码
    let counter = 1
    inputEl.oninput = _.debounce(function() {
        console.log(`发送网络请求${counter++}:`, this.value)
    }, 3000)

</script>

</body>
</html>

防抖基本功能实现:可以实现防抖效果

优化一:优化参数和this指向
优化二:优化取消操作(增加取消功能)
优化三:优化立即执行效果(第一次立即执行)
优化四:优化返回值

基本实现:

const hyDebounce = function (fn,delay){
        //1.第一次触发的timer
        let timer = null
        //2.触发执行后的函数
        const _debounce = function(...args){
            //如果再次触发,取消上一次的事件
            if (timer) clearTimeout(timer)
            //延迟执行对应的回调函数
            timer = setTimeout(()=>{
                fn()
                //执行完函数后timer置为null
                timer = null
            },delay)
        }
        //返回函数(闭包)
        return _debounce
    }

this优化

function hydebounce(fn, delay) {
  // 1.用于记录上一次事件触发的timer
  let timer = null

  // 2.触发事件时执行的函数
  const _debounce = function(...args) {
    // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
    if (timer) clearTimeout(timer)

    // 2.2.延迟去执行对应的fn函数(传入的回调函数)
    timer = setTimeout(() => {
      fn.apply(this, args)
      timer = null // 执行过函数之后, 将timer重新置null
    }, delay);
  }

  // 返回一个新的函数
  return _debounce
}

取消功能

    const hyDebounce = function (fn,delay){
        //1.第一次触发的timer
        let timer = null
        //2.触发执行后的函数
        const _debounce = function(...args){
            //如果再次触发,取消上一次的事件
            if (timer) clearTimeout(timer)
            //延迟执行对应的回调函数
            timer = setTimeout(()=>{
                //绑定this
                fn.apply(this,args)
                //执行完函数后timer置为null
                timer = null
            },delay)
        }

        //取消函数
        _debounce.cancel = function (){
            if(timer) clearTimeout(timer)
            timer = null
        }
        //返回函数(闭包)
        return _debounce
    }

立即执行功能

  // 原则: 一个函数进行做一件事情, 一个变量也用于记录一种状态
    const hyDebounce = function (fn,delay,immediate = true){
        //1.第一次触发的timer
        let timer = null
        let isInvoke = false

        //2.触发执行后的函数
        const _debounce = function(...args){
            //如果再次触发,取消上一次的事件
            if (timer) clearTimeout(timer)
            //第一次是否不需要延迟
            if(immediate && !isInvoke){
                fn.apply(this,args)
                isInvoke = true
                return
            }
            //延迟执行对应的回调函数
            timer = setTimeout(()=>{
                //绑定this
                fn.apply(this,args)
                //执行完函数后timer置为null
                timer = null
                isInvoke = false
            },delay)
        }

        //取消函数
        _debounce.cancel = function (){
            if(timer) clearTimeout(timer)
            timer = null
            isInvoke = false
        }
        //返回函数(闭包)
        return _debounce

获取返回值

   const hyDebounce = function (fn,delay,immediate = true){
        //1.第一次触发的timer
        let timer = null
        let isInvoke = false

        //2.触发执行后的函数
        const _debounce = function(...args){
          return new Promise((resolve,reject)=>{
              try {
                  //如果再次触发,取消上一次的事件
                  if (timer) clearTimeout(timer)
                  let res = undefined //返回值
                  //第一次是否不需要延迟
                  if(immediate && !isInvoke){
                      res = fn.apply(this,args)
                      resolve(res)
                      isInvoke = true
                      return
                  }
                  //延迟执行对应的回调函数
                  timer = setTimeout(()=>{
                      //绑定this
                      res = fn.apply(this,args)
                      resolve(res)
                      //执行完函数后timer置为null
                      timer = null
                      isInvoke = false
                  },delay)
              }catch (err){
                  reject(err)
              }
          })
        }

        //取消函数
        _debounce.cancel = function (){
            if(timer) clearTimeout(timer)
            timer = null
            isInvoke = false
        }
        //返回函数(闭包)
        return _debounce
    }

封装独立文件


// 原则: 一个函数进行做一件事情, 一个变量也用于记录一种状态
function hydebounce(fn, delay, immediate = false, resultCallback) {
  // 1.用于记录上一次事件触发的timer
  let timer = null
  let isInvoke = false

  // 2.触发事件时执行的函数
  const _debounce = function(...args) {
    return new Promise((resolve, reject) => {
      try {
        // 2.1.如果有再次触发(更多次触发)事件, 那么取消上一次的事件
        if (timer) clearTimeout(timer)

        // 第一次操作是不需要延迟
        let res = undefined
        if (immediate && !isInvoke) {
          res = fn.apply(this, args)
          if (resultCallback) resultCallback(res)
          resolve(res)
          isInvoke = true
          return
        }

        // 2.2.延迟去执行对应的fn函数(传入的回调函数)
        timer = setTimeout(() => {
          res = fn.apply(this, args)
          if (resultCallback) resultCallback(res)
          resolve(res)
          timer = null // 执行过函数之后, 将timer重新置null
          isInvoke = false
        }, delay);
      } catch (error) {
        reject(error)
      }
    })
  }

  // 3.给_debounce绑定一个取消的函数
  _debounce.cancel = function() {
    if (timer) clearTimeout(timer)
    timer = null
    isInvoke = false
  }

  // 返回一个新的函数
  return _debounce
}

节流

我们可以通过一幅图来认识这个过程
在这里插入图片描述
节流的应用场景
➢ 监听页面的滚动事件;
➢ 鼠标移动事件;
➢ 用户频繁点击按钮操作;
➢ 游戏中的一些设计

我们按照如下思路来实现:

 节流函数的基本实现:可以实现节流效果
 优化一:节流最后一次也可以执行
 优化二:优化添加取消功能
 优化三:优化返回值问题

基本实现

function myThrottle(fn,interval){
    let startTime = 0
    return _throttle = function (){
        let nowTime = new Date().getTime()
        let waitTime = interval - (nowTime - startTime)
        if(waitTime <= 0){
            fn()
            startTime = nowTime
        }
    }
}

this和参数绑定

function myThrottle(fn,interval){
    let startTime = 0
    return _throttle = function (...args){
        let nowTime = new Date().getTime()
        let waitTime = interval - (nowTime - startTime)
        if(waitTime <= 0){
            fn.apply(this,args)
            startTime = nowTime
        }
    }
}

对立即执行进行控制

引入一个变量 leading 对立即执行进行控制

function myThrottle(fn, interval, leading = true) {
  let startTime = 0
  return _throttle = function(...args) {
    let nowTime = new Date().getTime()
    // 控制是否立即执行
     if (!leading && startTime === 0) {
      startTime = nowTime
    }
    let waitTime = interval - ( nowTime - startTime)
  	if (waitTime <= 0) {
      fn.apply(this, args)
      startTime = nowTime
    }
  }
}

现有的封装好的
undercore
lodash

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值