手写防抖函数

简介: JS查漏补缺系列是我在学习JS高级语法时做的笔记,通过实践费曼学习法进一步加深自己对其的理解,也希望别人能通过我的笔记能学习到相关的知识点。这一次我们来试着手写防抖函数

简单实现

<input type="text">
<script src="./01_debounce-v1-基本实现.js"></script>
<script>
  const inputEl = document.querySelector("input")
  let counter = 0

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

  // 防抖处理
  inputEl.oninput = debounce(inputChange, 2000)
</script>
function debounce(fn, delay) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null

  // 2.真正执行的函数
  const _debounce = function() {
    // 取消上一次的定时器 
    // (不取消就会在最后一次性发送前面堆积的请求,而我们要实现的是到最后才请求一次)
    if (timer) clearTimeout(timer)
    // 延迟执行
    timer = setTimeout(() => {
      // 外部传入的真正要执行的函数
      fn()
    }, delay)
  }

  return _debounce
}

功能优化——this、参数改进

在原来的基础之上将inputChange修改了一下:

<script>
const inputChange = function(event) {
    console.log(`发送了第${++counter}次网络请求`,this,event)
}
</script>

直接用inputEl.oninput = inputChange触发得到:

用第三方库触发得到:
image.png
用我们上面手写的防抖函数得到:
image.png
可见的我们的函数对this和event的处理是有问题的。
改进:

function debounce(fn, delay) {
  let timer = null
  const _debounce = function(...args) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      // 用apply进行绑定this、arg
      fn.apply(this, args)
    }, delay)
  }

  return _debounce
}

功能优化——立即执行

:::info
功能实现:希望在第一次执行的时候就能给我立刻请求一次(可以选择立即执行/不立即执行)
:::
改进:

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)
      isInvoke = true 
    } else {
      timer = setTimeout(() => {
        fn.apply(this, args)
        isInvoke = false
      }, delay)
    }
  }

  return _debounce
}

功能优化——取消功能

:::info
场景:用户在输入东西之后防抖函数发送请求之前按到退出键退出了界面,这时我们就不用再发送请求
:::

<script>
// 取消功能
const cancelBtn = document.querySelector("#cancel")
cancelBtn.onclick = function() {
        debounceChange.cancel()
}
<script>
    // 封装取消功能
  _debounce.cancel = function() {
    if (timer) clearTimeout(timer)
    // 好习惯:取消或执行完毕后将默认值重置
    timer = null
    isInvoke = false
  }

功能优化——函数返回值

<script>
const inputChange = function(event) {
   console.log(`发送了第${++counter}次网络请求`, this, event)

   // 返回值
   return "aaaaaaaaaaaa"
}
  // 防抖处理
const debounceChange = debounce(inputChange, 3000, false, (res) => {
  console.log("拿到真正执行函数的返回值:", res)
})
</script>
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)
        isInvoke = true
      } else {
        timer = setTimeout(() => {
          const result = fn.apply(this, args)
          if (resultCallback) resultCallback(result)
          isInvoke = false
          timer = null
        }, delay)
      }
    })
  }

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

  return _debounce
}
目录
相关文章
|
4月前
15 # 手写 throttle 节流方法
15 # 手写 throttle 节流方法
36 0
|
10月前
节流函数和防抖函数的区别和应用
节流函数和防抖函数的区别和应用
31 0
|
11月前
|
前端开发
封装防抖函数和节流函数
封装防抖函数和节流函数
66 0
|
1月前
|
存储 前端开发 JavaScript
面试时让你手写一个防抖和节流优化,你能写出来吗?(二)
面试时让你手写一个防抖和节流优化,你能写出来吗?(二)
|
1月前
|
前端开发 UED
面试时让你手写一个防抖和节流优化,你能写出来吗?(一)
面试时让你手写一个防抖和节流优化,你能写出来吗?(一)
|
4月前
|
UED
函数防抖
在频繁触发的情况下,只有足够的空闲时间,才执行代码一次,如果没有执行完就清除掉,重新执行逻辑。简单来说,当触发后再次触发,会取消上一次触发的执行,直到最后一次触发后过去设定时间后才执行。
40 5
|
前端开发
手写防抖
手写防抖
56 0
|
4月前
14 # 手写 debounce 防抖方法
14 # 手写 debounce 防抖方法
39 1
|
4月前
|
前端开发 JavaScript UED
手写一个防抖
手写一个防抖
34 0
|
4月前
|
前端开发
【前端学习】—函数防抖(十)
【前端学习】—函数防抖(十)