函数防抖与节流实现及应用场景

205 阅读2分钟

函数防抖(debounce)

当函数被触发n秒后,再执行该函数,如果在这n秒内函数被再次触发,则重新计时

应用场景

连续的事件触发,只需要对最后一次进行处理

  • 搜索框搜索输入,只需要在用户输入完成后,再发起请求
  • 输入框进行输入验证检测
  • 对窗口进行resize调整,在调整完成后,再进行渲染

实现

function debounce(fn, wait) {
    var timer = null;
    return function () {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(() => fn.apply(this, arguments), wait);
    };
}

函数节流(throttle)

最少间隔n秒,执行一次函数

应用场景

  • 滚动加载
  • 高频点击提交

时间戳方式实现

function throttle(fn, wait) {
    // 初始时间设为0
    var prevTime = 0;
    return function () {
      // 获取当前时间
      let curTime = new Date();
      // 如果当前时间距离上次函数执行时间的时间间隔已经足够长了
      if (curTime - prevTime >= wait) {
        // 执行函数,通过apply绑定this,传递参数
        fn.apply(this, arguments);
        // 将当前时间戳赋值给上一次执行时间
        prevTime = curTime;
      }
    };
}

定时器方式实现

function throttle(fn, wait) {
    let timer = null;
    return function () {
      // 如果timer不为null,说明有函数正在等待执行,直接跳过
      if (timer) return;
      // 通过setTimeout,保证一定时间内只执行一次函数
      timer = setTimeout(() => {
        fn.apply(this, arguments);
        // 函数执行完成后,将timer清除
        timer = null;
      }, wait);
    };
  }

函数防抖和节流测试

简单的写了一个html页面测试,覆盖了函数防抖和节流的常见场景,input输入框输入即显示,提交按钮高频点击。codeSandbox链接

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  </head>
  <body>
    <input id="input" />
    <button type="button">提交</button>
    <div id="message"></div>
    <script src="./index.js"></script>
  </body>
</html>

// input输入框元素
let input = document.getElementById("input");
// 提交按钮元素
let submitBtn = document.querySelector("button");

// 函数防抖
function debounce(fn, wait) {
  let timer = null;
  return function () {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => fn.apply(this, arguments), wait);
  };
}

// 函数节流
function throttle(fn, wait) {
  let timer = null;
  return function () {
    if (timer) return;
    timer = setTimeout(() => {
      fn.apply(this, arguments);
      timer = null;
    }, wait);
  };
}

// 将input输入的内容显示在页面上
function handleInput(event) {
  let message = document.querySelector("#message");
  message.textContent = event.target.value;
}

// 通过控制台查看提交按钮触发的提交次数
function handleSubmit() {
  ++submitCount;
  console.log("提交次数:", submitCount);
}

let submitCount = 0;
// 监听input事件
input.addEventListener("input", debounce(handleInput, 1000));
// 监听点击事件
submitBtn.addEventListener("click", throttle(handleSubmit, 1000));