Skip to content

防抖与节流

防抖 debounce

基本概念

debounce(fn, timeout)

自最近触发一次后,延迟 timeout 时间调用 fn

应用场景

  • 调整页面的大小
  • 验证表单时控制请求次数
  • 防止表单多次提交

编写代码

假设一个场景,点击按钮后提交表单数据。为防止表单多次提交,设置点击按钮后延迟 2000ms 提交,自最近一次触发后再延迟提交。

debounce 函数中,接收两个参数,第一个参数为执行防抖的函数,第二个参数为防抖的延迟时间。将计时器记为 timer,每次执行函数之前清除之,则达到每次触发函数时都重新计时的效果。

在执行防抖的函数中执行 console.log(this),发现其指向 Windows。这时我们可以使用 apply 来把 this 的指向改变。

js
  const button = document.getElementById('button');

  function addOne() {
    console.log('add one');
    console.log(Date());
  }

  function debounce(fn, timeout) {
    let timer;
    return function () {
      clearTimeout(timer);
      timer = setTimeout(() => {
        fn.apply(this, arguments);
      }, timeout);
    };
  }

  button.addEventListener('click', debounce(addOne, 2000));

总而言之,防抖是在不断的操作中最终只执行一次的提高性能的方法。

节流 throttle

基本概念

throttle(fn, timeout)

timeout 时间内只调用一次 fn

应用场景

  • 搜索框实时联想
  • 监听 scroll 计算位置信息

编写代码

假设一个搜索框实时联想的场景,每隔 5s 向服务器发送一次查询。

throttle 函数中,第一个参数为执行节流的函数,第二个参数为节流的间隔时间。记录起始时间为 t1t2 为当前时间。如果当前时间距离上个时间的间隔大于设置的 timeout,则执行函数并且将 t1 记为上次函数发生的时间。

如前所述,使用 apply 来改变函数的指向。

js
  const input = document.getElementById('input');

  function trigger() {
    console.log(this.value);
  }

  function throttle(fn, timeout) {
    let t1 = 0;
    return function () {
      let t2 = new Date();
      if (t2 - t1 > timeout) {
        fn.apply(this, arguments);
        t1 = t2;
      }
    };
  }

  input.addEventListener('input', throttle(trigger, 5000));

总而言之,节流是在一段时间内操作只在规定的时间内执行一次的提高性能的方法。

Released under the MIT License.