您的位置:

JavaScript防抖函数的详细解析

一、js防抖函数怎么写

防抖函数的基本思路是在函数触发时,设定一个计时器来延迟执行函数,若在延时期间函数被再次触发,则重新计时,直到延时期满。这个计时器可以使用setTimeout来实现。具体实现如下所示:

function debounce(func, wait, immediate) {
  let timeout;
  return function() {
    const context = this;
    const args = arguments;
    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      timeout = null;
      if (!immediate) {
        func.apply(context, args);
      }
    }, wait);
    if (callNow) {
      func.apply(context, args);
    }
  };
}

以上代码中,debounce函数接收3个参数:需要延迟执行的函数、延迟的毫秒数以及一个布尔值,表示是否在函数被触发时立即执行函数。返回一个新函数,在调用这个新函数时就会延迟执行传入的函数。

二、js防抖函数和节流函数的区别

js中的防抖函数和节流函数都是为了解决函数频繁触发引起的性能问题,它们的区别在于:

  • 函数节流:一段时间内只能执行一次
  • 函数防抖:只有在上一次触发函数后的一段时间内没有再次触发,才会执行函数

简单说,函数节流的思路是:以一定时间间隔来执行函数,而函数防抖的思路是:在一定时间段内不允许函数执行,直到时间结束后再执行。

三、js防抖函数立即执行

在前面的js防抖函数中,我们实现的是延迟执行函数,如果要实现立即执行函数,可以根据传入的第3个参数immediate。当immediate为true时,函数立即执行,当immediate为false或不传时,函数延迟执行。

 function debounce(func, wait, immediate) {
   let timeout;
   return function() {
     const context = this;
     const args = arguments;
     clearTimeout(timeout);
     if (immediate) {
       const callNow = !timeout;
       timeout = setTimeout(function() {
         timeout = null;
       }, wait);
       if (callNow) {
         func.apply(context, args);
       }
     } else {
       timeout = setTimeout(function() {
         func.apply(context, args);
       }, wait);
     }
   }
 }

四、js按钮防抖函数

在前端页面中,按钮可能会被用户频繁的点击,导致后端接口被频繁地调用,可能会造成系统崩溃。为了解决这个问题,我们可以使用js防抖函数来实现防止按钮被频繁点击的效果。

function debounceButton(func, wait) {
  let timeout;
  return function() {
    const context = this;
    const args = arguments;
    if (timeout) clearTimeout(timeout);
    const callNow = !timeout;
    timeout = setTimeout(function() {
      timeout = null;
    }, wait);
    if (callNow) {
      func.apply(context, args);
    }
  };
}

以上代码中的debounceButton函数接收2个参数:需要防抖的函数以及延迟的毫秒数。返回一个新函数,在调用这个新函数时就会延迟执行传入的函数。

五、js防抖函数不会重置闭包的变量吗

在防抖的实现中会使用闭包来缓存定时器,那么就会引起一个问题:闭包中的变量是不是每次调用防抖函数都会被重置?答案是不会。

当我们多次调用防抖函数时,每一个闭包都会持有一份独立的timeout变量,它们之间是相互独立的,互不干扰。这就是js闭包的神奇之处。

六、vue防抖函数

在vue中,可以使用官方提供的工具库lodash来实现防抖函数。在模板里面可以使用v-debounce指令来调用防抖函数,在后台API请求中就可以避免频繁地向服务器请求数据了。

import { debounce } from "lodash";

export default {
  data() {
    return {
      value: ""
    };
  },
  methods: {
    search: debounce(function(query) {
      console.log(query);
    }, 500)
  }
};

七、实现一个防抖函数

以下是一个简单的防抖函数的代码实现:

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

此实现中,第一个参数func是需要防抖的函数,delay是防抖时间。返回一个新函数,调用这个新函数时就会延迟执行传入的函数,若在延时期间函数被再次触发,则重新计时,直到延时期满。

八、js防抖写法

以下是一种简单的js防抖写法:

function debounce(fn, wait) {
  return function() {
    clearTimeout(fn.timeoutId);
    fn.timeoutId = setTimeout(() => {
      fn.apply(this, arguments);
    }, wait);
  };
}

在这种写法中,将timeoutId作为fn函数的一个属性以缓存定时器。如果在定时器还没完成时fn又被执行,则清除之前的计时器重新计时。最后执行函数fn。

九、js防抖和节流代码

以下是一种防抖和节流代码结合的写法:

function throttleDebounce(fn, wait1, isDebounce, wait2) {
  let timeoutId, lastExecTime;
  return function() {
    const context = this;
    const args = arguments;
    const elapsedTime = Date.now() - lastExecTime;

    const execFunc = () => {
      lastExecTime = Date.now();
      fn.apply(context, args);
    };

    if (isDebounce) {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(execFunc, wait1);
    } else if (elapsedTime > wait1) {
      execFunc();
    } else {
      clearTimeout(timeoutId);
      timeoutId = setTimeout(execFunc, wait2);
    }
  };
}

在这个函数中,有4个参数:需要防抖或节流的函数,防抖时间,是否是防抖模式,节流时间。返回一个新函数,在调用这个新函数时就会延迟执行或者限流后执行传入的函数。

十、函数节流和函数防抖选取

在实际开发中,如何选择函数节流和函数防抖呢?

  • 如果想要限制函数在一定时间段内只被调用一次,则使用函数节流;
  • 如果想要在一段时间内只允许函数执行一次,则使用函数防抖。

举个例子,如果我们想要执行一个输入框的验证,我们可以使用函数防抖,当用户连续输入时,不会实时反馈验证结果,而是在用户输入(或停止输入)一段时间后,才进行验证。

再举个例子,当用户频繁滚动页面时,我们可以使用函数节流,每隔一定时间(比如100毫秒)才执行一次处理滚动事件的函数,避免因为这个事件的频繁触发导致性能问题。

选择函数节流还是函数防抖取决于你的场景需求,需要在实际开发中进行权衡取舍。