js笔记-手写防抖函数

159 阅读2分钟

什么是防抖函数

防抖函数用于限制触发函数或网络请求的次数,例如百度搜索中,当按下键盘之后会在一定时间内确认不在输入时再发送网络请求。
防抖函数的实现(1),思路是通过定时器来执行函数
function debounce(fn, delay) {
  // 定义一个定时器,保存上一次的定时器
  let timer = null

  // 真正执行的函数
  const _debounce = function(...args) {
    // 取消上一次执行的定时器
    if(timer) clearTimeout(timer)

    // 延迟执行
    timer = setTimeout(() => {
      // 外部传入的正真正要执行的函数,绑定this和参数
      fn.apply(this, args)
    }, delay)
  }

  return _debounce
}
防抖函数的实现(2) 增加一个参数是否可以立即执行一次
function debounce(fn, delay, immediate = false) {
  // 定义一个定时器,保存上一次的定时器
  let timer = null
  let isInvoke = false

  // 真正执行的函数
  const _debounce = function (...args) {
    // 取消上一次执行的定时器
    if (timer) clearTimeout(timer)

    // 判断是否立即执行
    if (immediate && !isInvoke) {
      fn.apply(this, args)
      // immediate = false
      isInvoke = true
    } else {
      // 延迟执行
      timer = setTimeout(() => {
        // 外部传入的正真正要执行的函数,绑定this和参数
        fn.apply(this, args)
        isInvoke = false
      }, delay)
    }
  }

  return _debounce
}
防抖函数的实现(3) 增加一个取消执行的功能
function debounce(fn, delay, immediate = false) {
  // 定义一个定时器,保存上一次的定时器
  let timer = null
  let isInvoke = false

  // 真正执行的函数
  const _debounce = function (...args) {
    // 取消上一次执行的定时器
    if (timer) clearTimeout(timer)

    // 判断是否立即执行
    if (immediate && !isInvoke) {
      fn.apply(this, args)
      // immediate = false
      isInvoke = true
    } else {
      // 延迟执行
      timer = setTimeout(() => {
        // 外部传入的正真正要执行的函数,绑定this和参数
        fn.apply(this, args)
        isInvoke = false
      }, delay)
    }
  }

  _debounce.cancel = function() {
    if(timer) clearTimeout(timer)
    timer = null
  }

  return _debounce
}
防抖函数的实现(4) 拿到函数的返回值
function debounce(fn, delay, immediate = false, resultCallback) {
  // 定义一个定时器,保存上一次的定时器
  let timer = null
  let isInvoke = false

  // 真正执行的函数
  const _debounce = function (...args) {
    // 取消上一次执行的定时器
    if (timer) clearTimeout(timer)

    // 判断是否立即执行
    if (immediate && !isInvoke) {
      const result = fn.apply(this, args)
      if(resultCallback) resultCallback(result)
      // immediate = false
      isInvoke = true
    } else {
      // 延迟执行
      timer = setTimeout(() => {
        // 外部传入的正真正要执行的函数,绑定this和参数
        const result = fn.apply(this, args)
        if(resultCallback) resultCallback(result)
        isInvoke = false
      }, delay)
    }
  }

  _debounce.cancel = function() {
    if(timer) clearTimeout(timer)
    timer = null
  }

  return _debounce
}

HTML部分

<!DOCTYPE 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">
    <button id="cancel">取消</button>

    <script src="./01_防抖函数的基本实现.js"></script>

    <script>
      const inputEl = document.querySelector("input")
      const btn = document.querySelector("#cancel")

      let counter = 0

      const inputChange = function () {
        console.log(`发送了第${++counter}次网络请求`);

        return 'aaa'
      }

      const debounceChange = debounce(inputChange, 2000, true, (res) => {
        console.log(res);
      })

      inputEl.oninput = debounceChange
      btn.onclick = debounceChange.cancel
    </script>
</body>
</html>