回到课程

防抖装饰器

重要程度: 5

debounce(f, ms) 装饰器的结果是一个包装器,该包装器将暂停对 f 的调用,直到经过 ms 毫秒的非活动状态(没有函数调用,“冷却期”),然后使用最新的参数调用 f 一次。

换句话说,debounce 就像一个“接听电话”的秘书,并一直等到 ms 毫秒的安静时间之后,才将最新的呼叫信息传达给“老板”(调用实际的 f)。

举个例子,我们有一个函数 f,并将其替换为 f = debounce(f, 1000)

然后,如果包装函数分别在 0ms、200ms 和 500ms 时被调用了,之后没有其他调用,那么实际的 f 只会在 1500ms 时被调用一次。也就是说:从最后一次调用开始经过 1000ms 的冷却期之后。

……并且,它将获得最后一个调用的所有参数,其他调用的参数将被忽略。

以下是其实现代码(使用了 Lodash library 中的防抖装饰器 ):

let f = _.debounce(alert, 1000);

f("a");
setTimeout( () => f("b"), 200);
setTimeout( () => f("c"), 500);
// 防抖函数从最后一次函数调用以后等待 1000ms,然后执行:alert("c")

现在我们举一个实际中的例子。假设用户输入了一些内容,我们想要在用户输入完成时向服务器发送一个请求。

我们没有必要为每一个字符的输入都发送请求。相反,我们想要等一段时间,然后处理整个结果。

在 Web 浏览器中,我们可以设置一个事件处理程序 —— 一个在每次输入内容发生改动时都会调用的函数。通常,监听所有按键输入的事件的处理程序会被调用的非常频繁。但如果我们为这个处理程序做一个 1000ms 的 debounce 处理,它仅会在最后一次输入后的 1000ms 后被调用一次。

在这个实时演示的示例中,处理程序将结果显示在了下面的方框中,试试看:

看到了吗?第二个输入框调用了防抖函数,所以它的内容是在最后一次输入的 1000ms 后被处理的。

因此,debounce 是一个处理一系列事件的好方法:无论是系列键盘输入,鼠标移动还是其他类似的事件。

它在最后一次调用之后等待给定的时间,然后运行其可以处理结果的函数。

任务是实现一个 debounce 装饰器。

提示:如果你好好想想,实现它只需要几行代码 :)

打开带有测试的沙箱。

function debounce(func, ms) {
  let timeout;
  return function() {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, arguments), ms);
  };
}

调用 debounce 会返回一个包装器。当它被调用时,它会安排一个在给定的 ms 之后对原始函数的调用,并取消之前的此类超时。

使用沙箱的测试功能打开解决方案。