阅读 342

JavaScript 函数防抖了解一下

说到防抖,想必多数人首先想到的是相机的防抖。因为我们并不是机器人,所以拿手机拍照的时候,手都会有不易察觉的抖动,这样的抖动会影响相片的质量。手机对这些情况做的一些补偿操作,减小了手抖对成像造成的影响。

我们都知道,JavaScript 是一门编程语言,不是人类也不是机器人。那什么情况下,会产生“抖动”呢?

场景

联想一个平平无奇的搜索框,当用户输入的时候,需要实时给出搜索建议。

第一反应肯定是监听输入框的 input 事件,随着内容的变化,发出请求,拉取建议的数据。

如下面的例子(这里 input 被触发时,执行 console.log('input'), 并且用 console.log('fetch') 代指请求):

可以看到,每一个字符的增减,都会触发请求。

这种情况,就属于“抖动”。

服务器接收到这样的请求,肯定是一脸懵啊,这谁顶得住?

这个时候,就需要像手机相机一样,做一些操作,减少抖动对网络请求的影响,减轻服务器的压力。

怎么做

“抖动”情景下,连续输入,导致发送了多次一样的请求。函数防抖的处理方式是:先规定一个时间段,比如一秒,输入内容触发 input ,一秒之后再发送请求,假如一秒内又产生了新的输入,那么重新计时,点击过后一秒再发送请求。

这样一来,规定时间段内的所有输入,只会产生一次请求。不管打字多快的手速,也战胜不了防抖的函数。

怎么写

直接上代码:

const debounce = (func, delay = 200) => {
  let timeout = null
  return function () {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
      func.apply(this, arguments)
    }, delay)
  }
}
复制代码

debounce 函数接受一个函数 func 和一个默认为 200 毫秒延迟时间 delay 作为参数。返回一个函数,触发返回的函数,开始计时,delay 毫秒后触发 func, 假如 delay 时间段内,再次触发这个函数,那么重新计时,delay 毫秒后触发 func.

debounce 首先声明变量 timeout, 用于存放之后 setTimeout 函数返回的定时器编号。

然后返回一个函数,函数内执行 clearTimeout 来依据先前声明的 timeout 来清除定时器。当然,一开始,传入的 timeout 值为 null, 这时的清除操作忽略不计。

接着,执行 setTimeout, 在至少 delay 规定的毫秒后,将 setTimeout 的回调函数添加到当前事件队列,回调内执行 func 函数。并且把返回的定时器编号赋值给 timeout , 这样,下一次触发 debounce 返回的函数时,就可以清除通过上面的 clearTimeout(timeout) 来清除定时器 。

注意到上面执行 func 用的是 func.apply(this, arguments), 这样一来,就可以对 debounce 返回的那个函数传递参数,func 执行的时候,再把参数传给 func.

来用一下:

const suggest = () => {
  console.log('fetch')
}

const debounceSuggest = debounce(suggest, 500)

let btnSearch = document.getElementById('search')
btnSearch.addEventListener('input', () => {
  console.log('input')
  debounceSuggest()
})
复制代码

这里将 suggest 函数传入 debounce 函数,并设置延迟时间为 500 毫秒。 debounce 返回的函数赋给 debounceSuggest , 然后在提交按钮 btnSearchinput 事件回调中执行 debounceSuggest.

看下效果:

上图中,一开始的几次连续输入,都不会触发 suggest,打印 fetch ,直到整个单词 'hello' 输入完成,才触发了一次 suggest. 接着连续删除,也只触发了一次 suggest.

总结

函数的防抖将一定时间内的多次操作,减少为一次,去除冗余,节约资源。

关注下面的标签,发现更多相似文章
评论