手写防抖函数

104 阅读2分钟

手写防抖函数

将自己的理解和知识点写在代码注释中.(习惯了)

debounce-v1-基本实现

function debounce(fn, delay = 1000) {
  // 定义定时器,保存上一次的定时器
  let timer = null
  function _debounce(){
    // 取消上一次的定时器
    if(timer) clearTimeout(timer)
    // 延迟执行
    timer = setTimeout(() => {
      // 真正要执行的函数
      fn()
    }, delay);
  }
  
  return _debounce
}

debounce-v2-this-参数

function debounce(fn, delay = 1000) {
  // 定义定时器,保存上一次的定时器
  let timer = null
  function _debounce(...args){
    // 取消上一次的定时器
    if(timer) clearTimeout(timer)
    // 延迟执行
    timer = setTimeout(() => {
      // 真正要执行的函数
      fn.apply(this, args)
    }, delay);
  }
  return _debounce
}

debounce-v3-立即执行

function debounce(fn, delay = 1000, immediate = false) {
  // 定义定时器,保存上一次的定时器
  let timer = null
  // 判断是否需要执行
  let isInvoke = false

  function _debounce(...args){
    // 取消上一次的定时器
    if(timer) clearTimeout(timer)

    // 判断是否需要立即执行
    if(immediate && !isInvoke){
      fn.apply(this, args)
      isInvoke = true
      timer = null
    }

    // 延迟执行
    timer = setTimeout(() => {
      // 真正要执行的函数
      fn.apply(this, args)
      isInvoke = false
    }, delay);
  }

  return _debounce
}

debounce-v4-取消功能

function debounce(fn, delay = 1000, immediate = false) {
  // 定义定时器,保存上一次的定时器
  let timer = null
  // 判断是否需要执行
  let isInvoke = false

  function _debounce(...args){
    // 取消上一次的定时器
    if(timer) clearTimeout(timer)

    // 判断是否需要立即执行
    if(immediate && !isInvoke){
      fn.apply(this, args)
      isInvoke = true
      timer = null
    }

    // 延迟执行
    timer = setTimeout(() => {
      // 真正要执行的函数
      fn.apply(this, args)
      isInvoke = false
    }, delay);
  }

  // 封装取消功能
  _debounce.cancel = () => {
    if(timer){
      clearTimeout(timer)
      timer = null
      isInvoke = false
    }
  }

  return _debounce
}

debounce-v5-函数返回值

function debounce(fn, delay = 1000, immediate = false, resultCallback) {
  // 定义定时器,保存上一次的定时器
  let timer = null
  // 判断是否需要执行
  let isInvoke = false

  function _debounce(...args){
    // 取消上一次的定时器
    if(timer) clearTimeout(timer)

    // 判断是否需要立即执行
    if(immediate && !isInvoke){
      const result = fn.apply(this, args)
      if(resultCallback && result && typeof resultCallback === 'function') {
        resultCallback(result)
      }
      isInvoke = true
      timer = null
    }

    // 延迟执行
    timer = setTimeout(() => {
      // 真正要执行的函数
      const result = fn.apply(this, args)
      if(resultCallback && result && typeof resultCallback === 'function') {
        resultCallback(result)
      }
      isInvoke = false
    }, delay);
  }

  // 封装取消功能
  _debounce.cancel = () => {
    if(timer){
      clearTimeout(timer)
      timer = null
      isInvoke = false
    }
  }

  return _debounce
}

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" placeholder="请输入商品名~" />
    <button id="btn">取消</button>

    <!-- <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.2/underscore-umd-min.js"></script> -->
    <!-- <script src="./01_debounce-v1-基本实现.js"></script> -->
    <!-- <script src="./02_debounce-v2-this-参数.js"></script> -->
    <!-- <script src="./03_debounce-v3-立即执行.js"></script> -->
    <!-- <script src="./04_debounce-v4-取消功能.js"></script> -->
    <script src="./05_debounce-v5-函数返回值.js"></script>
    <script>
      const inputEl = document.querySelector("input");
      let index = 0;

      const inputFn = function (event) {
        console.log(`执行第${++index}次`, this, event);
        return "aaaaa";
      };

      /// 1.深刻理解: 回城防抖 平A节流

      // 2.underscore库的使用
      // 防抖处理
      // const newInputFn = _.debounce(inputFn, 1000);
      // 节流处理
      // const newInputFn = _.throttle(inputFn, 1000);

      // 3.自己手写防抖
      const newInputFn = debounce(inputFn, 2000, true, (res) => {
        console.log("拿到函数的返回值:", res);
      });

      inputEl.addEventListener("input", newInputFn);

      // 取消功能
      const btnEl = document.querySelector("#btn");
      btnEl.addEventListener("click", () => {
        newInputFn.cancel();
      });
    </script>
  </body>
</html>