# 防抖函数

# 面试中我们经常遇到手写一个简单的防抖函数

防抖函数的核心思路如下:

  • 当触发一个函数时,并不会立即执行这个函数,而是会延迟(通过定时器来延迟函数的执行)

    • 如果在延迟时间内,有重新触发函数,那么取消上一次的函数执行(取消定时器);
    • 如果在延迟时间内,没有重新触发函数,那么这个函数就正常执行(执行传入的函数);

接下来,就是将思路转成代码即可:

  • 定义debounce函数要求传入两个参数

    • 需要处理的函数fn
    • 延迟时间;
  • 通过定时器来延迟传入函数fn的执行

    • 如果在此期间有再次触发这个函数,那么clearTimeout取消这个定时器;
    • 如果没有触发,那么在定时器的回调函数中执行即可;
function debounce(fn, delay) {
  var timer = null;
  return function() {
    if (timer) clearTimeout(timer);
    timer = setTimeout(function() {
      fn();
    }, delay);
  }
}

注意:当我第一次看到这个代码是还是有点蒙圈,当时我以为var timer=null每次调用这个防抖函数时都会执行赋值操作,但是实际上并不是这样的,var timer=null只是对变量timer进行初始化操作。这里还用到了函数闭包,只要return后面返回的函数没有执行完毕,则timer变量会一直保持在栈空间中,不会被销毁。所以在这里timer变量只会被初始化一次,也就是第一次执行debounce防抖函数才会执行var timer=null的初始化赋值操作。

# 下面是另一个版本
//setTimeout()函数来让函数延迟执行

const ipt = document.querySelector('input')//1.获取dom
let timeout = null//2.初始化timeout变量
ipt.addEventListener('input',e=>{//3.被重复调用需要防抖处理的函数
    if(timeout){
        clearTimeout(timeout)//5.清除定时器
        timeout = null
    }
    timeout = setTimeout(()=> {//4.对timeout变量赋值为一个定时器
        search(e.target.value).then(resp => {
            //..
        },e=>{
            //..
        })
    },500)
})

这个就更好理解一点了,我们来读一下代码,代码中的3、4、5步骤都是会因为防抖被重复调用的。

第一次timeout初始化为空,if(timout)里面的内容不执行,对timeout进行赋值定时器;如果定时器的时间没有过(定时器中的函数没有被执行),此时再次激活监听的事件,timeout不为空,所以if(timout)里面的内容会被执行,然后之前的定时器被清除,然后又去设置新的定时器,直到定时器时间过了,执行消息队列消息。

# 总结

函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。

函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。

区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

Last Updated: 7/15/2020, 10:34:45 PM