JS怎么防抖?

485 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Prerequisite: JS函数、setTimeout

什么是debounce?

debounce防抖,是一个被广泛应用于交互应用中的技术,用来过滤一串快速发生的无效事件(抖动)。

举个例子:一个输入框,我们希望用户输入完成以后自动发起搜索。简单的方法是,监听用户的输入事件,每次用户改变输入,我们就发起请求查询用户的输入内容。然而,这样做很明显会造成极大的浪费。用户输入hello,实际上我们已经发起了五次请求,分别查询

h
he
hel
hell
hello

那么,有没有更好的方法能恰好在用户停止输入(一段时间)以后才发起查询请求呢?这就是debounce防抖,过滤一系列快速发生的事件,只保留一串事件中最后一次触发的事件

代码实现

debounce函数,可以将任何函数封装为“防抖”函数。先看代码,解释在后面!

function debounce (func, timeout = 300) {
  let timer
  return (...args) => {
    clearTimeout(timer)
    timer = setTimeout(() => { func.apply(this, args) }, timeout)
  }
}

将实际执行的函数作为第一个参数传入debounce,保存封装的“防抖”函数。调用时调用“防抖”函数即可。

使用案例:

const print = debounce(m => console.log(m), 500)
print('hello')
print('can you see this?')
print('hi')
setTimeout(() => { print('amazing!') }, 1000)

控制台的输入结果如下:

hi
amazing!

前三个print连续触发,只有最后一个被实际执行。停顿1秒超出timeout以后,再次触发即可重新执行。

解析

function debounce (func, timeout = 300) {

函数头部,接受两个参数,第一个为实际执行的函数,第二个为timeout毫秒数。

  let timer

定义变量timer用于保存计时器。请注意这个变量的定义位置,它在返回的“防抖”函数之外。也就意味着每次调用的“防抖”函数将共享这个变量。

  return (...args) => {

返回防抖函数头部,接收任意参数表,因此适用于任何被封装的函数。

    clearTimeout(timer)

无论以前是否有触发“防抖”函数,清除掉以前的触发留下的计时器。若上次触发还没有实际执行(在timeout时间内),则上次触发将被打断,不会被实际执行。

    timer = setTimeout(() => { func.apply(this, args) }, timeout)

设置计时器为本次触发的内容,若不被另一个触发打断(clearTimeout),将在timeout时间以后被实际执行,触发时传入的参数也将被传入到实际执行的函数中。