你真的会防抖吗?

88 阅读2分钟

原理是什么?

忽略重复事件,通过设置定时器,等待一定时间后执行事件处理函数,如果在这段时间内又触发了相同的事件,则重新计时。

用来解决什么问题

解决由于频繁触发事件引起的性能问题,例如表单提交,输入框搜索,页面滚动。

⚠️ 秒杀按钮是防抖吗? 答:不是,如果设置防抖那么大量的请求还是会在同一时间发过来,服务器还是会处理大量请求的压力。应该通过设置节流让他按照一定频率执行,因为用户没抢到是要一直抢的,如果使用防抖,用户的点击只会被响应一次,影响用户体验。。


表单提交一定会用防抖吗? 答:实际项目中一般在点击之后将按钮置为disable状态,防止用户的频繁点击,在提交成功之后再重新置为可点击态。


实现

不带参数

  function debounce(fn, delay) {
  //初始化定时器
     let timer;
     return function() {
     //清除最后一次操作之前的定时器
     clearTimeout(timer)
       timer = setTimeout(() => {
       //在延迟对应描述之后执行
         fn()
       }, delay)
     }
  }

需要考虑参数

function debounce(func, wait) {
 let timer;
 return function() {
   const context = this;
   const args = arguments;
   clearTimeout(timer);
   timer = setTimeout(() => {
     func.apply(context, args);
   }, wait);
 };
}

需要指定作用域

前两种已经可以满足大多数需求了,但是面试官提到这种情况。

 const obj = {
  id: '23123',
  getName: function (name){
      return function() {
          console.log(`id: ${this.id}, name: ${name}`);
      }
  }
};

let person = obj.getName('xiaoming')
let handleClick = debounce(person, 1000)
handleClick() //id: undefined, name: xiaoming

由于是在全局环境执行的所以id还是undefine,

解决方法

防抖函数中加入要绑定的对象

function debounce(func, wait, ctx) {
  let timeout;
  let context;
  return function() {
    context = ctx ? ctx : this
    const args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      func.apply(context, args);
    }, wait);
  };
let person = obj.getName('xiaoming')
let handleClick = debounce(person, 1000, obj)
handleClick() //id: 23123, name: xiaoming
//直接将person绑定到obj也是可以的 但是如果在debounce里实现的话可以多传一个参数
//let person = obj.getName('xiaoming').bind(obj)

实际应用

html中


<!DOCTYPE html>
<html>
<head>
   <title>防抖</title>
</head>
<body>
   <h2>防抖</h2>
   <button class="button">防抖</button>
</body>
<script>
function debounce(func, wait) {
 let timeout;
 return function() {
   const context = this;
   const args = arguments;
   clearTimeout(timeout);
   timeout = setTimeout(() => {
     func.apply(context, args);
   }, wait);
 };
}
const button = document.querySelector('button');
button.addEventListener('click', debounce(function() {
 console.log('点击了防抖')
}, 1000));
</script>
</html>

Vue中

  <template>
    <button @click="handleClick">防抖</button>
  <template>
  <script> 
    debounce(fn, delay) {
        let timer 
        return function() {
          clearTimeout(timer)
          timer = setTimeout(() => {
            fn()
          }, delay)
        }
      },
      // 这
      handleClick: debounce(function() {
        console.log('sf')
      }, 2000)
  <script>