ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

温顾篇 —— JS(函数防抖debounce)

2021-12-26 16:01:23  阅读:206  来源: 互联网

标签:function 防抖 函数 debounce 温顾篇 timer ipt fn


温顾篇 —— JS(函数防抖debounce)

温顾篇 —— JS(函数防抖debounce)

在前端中有一些原生事件会频繁的触发从而容易造成页面的卡顿,例如:

  • window 的 resize、scroll(页面滚动加载等)
  • mousedown、mousemove
  • keyup、keydown
  • input 的 input 事件(调用接口查询等)

接下来我就用原生来简单写下js函数的防抖:

<!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>
  <input type="text" class="ipt">
  <script>
    function debounce(fn, delay) {
      let timer = null;
      return function (e) {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          // 这里最好不要直接调用fn fn(), 因为this指向window 而且event事件是undefined
          fn()
          // fn.apply(this, arguments)
        }, delay)
      }
    }
    // 获取节点
    let ipt = document.querySelector('.ipt')
    // 绑定事件触发防抖函数
    ipt.addEventListener('input', debounce(function (event) {
      console.log('this', this);
      console.log('event', event);
    },5000))
  </script>
</body>

</html>

注意:如果防抖函数中直接调用fn函数,则会出现如下this的指向问题和绑定事件的event为undefined;
在这里插入图片描述
还有这里传入的函数,也不要是箭头函数,也会导致this指向window;
在这里插入图片描述

<!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>
  <input type="text" class="ipt">
  <script>
    function debounce(fn, delay) {
      let timer = null;
      return function (e) {
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          // 这里最好不要直接调用fn fn(), 因为this指向window 而且event事件是undefined
          // fn()
          fn.apply(this, arguments)
        }, delay)
      }
    }
    // 获取节点
    let ipt = document.querySelector('.ipt')
    // 绑定事件触发防抖函数
    ipt.addEventListener('input', debounce(function (event) {
      console.log('this', this);
      console.log('event', event);
    },5000))
  </script>
</body>

</html>

注意:调用时 使用apply改变函数的this指向,fn.apply(this, arguments)
在这里插入图片描述

解析如下:

<!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>
  <input type="text" class="ipt">
  <script>
    function debounce(fn, delay) {
      return function (e) {
        console.log('debounce 函数执行了');
      }
    }
    
    // 获取节点
    let ipt = document.querySelector('.ipt')
    // 绑定事件触发防抖函数 addEventListener调用的是函数,所以debounce需要返回一个函数
    // 这里只会返回debounce函数中的逻辑, 并不会打印 console.log('发送请求');
    ipt.addEventListener('input', debounce((event) => {
      console.log('发送请求');
    }, 5000))
  </script>
</body>

</html>

在这里插入图片描述
1、如果想触发打印 console.log('发送请求'); 怎么办呢?

在return返回的函数中执行fn函数既可;

在这里插入图片描述2、如果不想立即执行fn函数,怎么办呢?

这时候想到可以用个定时器来控制,这时候就可以控制什么时候执行fn函数

<!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>
  <input type="text" class="ipt">
  <script>
    function debounce(fn, delay) {
      return function (e) {
        console.log('debounce 函数执行了');
        setTimeout(() => {
          fn()
        }, delay)
      }
    }
    
    // 获取节点
    let ipt = document.querySelector('.ipt')
    // 绑定事件触发防抖函数 addEventListener调用的是函数,所以debounce需要返回一个函数
    ipt.addEventListener('input', debounce((event) => {
      console.log('发送请求');
    }), 5000)
  </script>
</body>

</html>

3、如果不想调用fn函数多次呢?

判断定时器是否存在,存在则清掉之前的定时器

<!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>
  <input type="text" class="ipt">
  <script>
    function debounce(fn, delay) {
      let timer = null;
      return function (e) {
        console.log('debounce 函数执行了');
        if (timer) {
          clearTimeout(timer)
        }
        timer = setTimeout(() => {
          fn()
        }, delay)
      }
    }
    // 获取节点
    let ipt = document.querySelector('.ipt')
    // 绑定事件触发防抖函数 addEventListener调用的是函数,所以debounce需要返回一个函数
    ipt.addEventListener('input', debounce((event) => {
      console.log('发送请求');
    }, 5000))
  </script>
</body>

</html>

防抖函数如下:

function debounce(fn, delay) {
  let timer = null;
  return function (e) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      // 这里最好不要直接调用fn fn(), 因为this指向window 而且event事件是undefined
      fn.apply(this, arguments)
    }, delay)
  }
}

// 传参不同
function debounce(fn, delay) {
  let timer = null;
  return function (...args) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      // 这里最好不要直接调用fn fn(), 因为this指向window 而且event事件是undefined
      fn.apply(this, args)
    }, delay)
  }
}

标签:function,防抖,函数,debounce,温顾篇,timer,ipt,fn
来源: https://blog.csdn.net/weixin_42681295/article/details/122155575

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有