场景

我们可以想象一下,有一个登录或搜索按钮,点了之后会调用后台接口,如果一直点就一直调用,但是这样可能会对服务器造成压力,并且短时间内多次请求后台也是没啥意义的事情,这是是一个非常耗费资源的行为,由此就出现了防抖的解决方案。

简介

debounce 是解决防抖问题的一个通用方案。

它的原理大致是:创建一个函数,并存储 setTimeout 返回的标识用于后续清除它,内部返回一个闭包函数,闭包函数内部使用 setTimeout 调用目标函数。

它实现的效果为:强制一个函数在某个连续时间段内只执行一次。(即 1 秒内(假设时间),不管调用多少次,只会执行最后一次的调用)

如果使用过 lodash 中的 debounce 函数,你会发现,他实际上是最终解决方案,即最为全面的 debounce 函数,因为基本上网络上搜索到的 debounce 函数都只有两个参数,而它却有三个参数,不过一般情况下,两个参数就够了,即一个要执行的目标函数和指定的时间范围 。

基础知识

…args

rest 参数

func.apply(this, … args)

apply

闭包

相关知识可以参考

  1. MDN 闭包
  2. 阮一峰老师的 javascript 教程之闭包
  3. javascript.info 闭包

    代码

    1. const debounce = (func, wait) => {
    2. let timeout;
    3. return function executedFunction(...args) {
    4. const later = () => {
    5. timeout = null;
    6. func.apply(this, ...args);
    7. };
    8. clearTimeout(timeout);
    9. timeout = setTimeout(later, wait);
    10. };
    11. };

    分析

    第 1 行代码声明了接受两个参数的 debounce 函数,func 代表真正要执行的目标函数wait 是一个延迟调用的时间,单位为毫秒。
    第 2 行代码声明了 timeout 变量,用于存储后续开启 setTimeout 返回的标识。
    第 3 行代码返回了一个闭包函数,参数为 …args,这个 rest 参数代表了实际执行的目标函数的参数列表
    第 5-9 行代码声明了一个函数用于包装实际要执行的目标函数timeout = null 的意义在于,避免被 cleartTimeout。使用 func.apply(this, …args) 这样的方法去调用实际执行的目标函数,因为 func 也就是我们实际要执行的目标函数,内部是拿不到 this 值的,所以这里需要用 apply() 方法执行一个 this 值。
    第 11 行代码使用 clearTimeout 来清除上一次发起的 setTimeout,只有清除上一次的,才能保证指定时间内,只执行一次也就是只令最后一次调用生效。
    第 12 行代码使用 setTimeout 开启一个延时执行任务,这样保证了实际要执行的目标函数不会立即执行,而是在 wait 毫秒之后执行,同样很关键,其实最最核心的就是 clearTimeout 和 这个 setTimeout,没有最后这两行代码就无法实现防抖。