今天看啥  ›  专栏  ›  菲利普马洛

JavaScript 函数防抖了解一下

菲利普马洛  · 掘金  ·  · 2019-06-30 03:42
阅读 25

JavaScript 函数防抖了解一下

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

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

场景

联想一个平平无奇的登录框,当用户信息输入完毕,点击登录按钮,可能网速有点慢还是啥的,用户等得不耐烦,不停点击,导致鼠标患上帕金森,登录按钮就被一次一次地点击,前端不停地向后台发送重复的请求。

如下面的例子(这里点击一次,执行 console.log('click'), 并且用 console.log('submit') 代指请求):

可以看到,短时间内连续点击,每次点击都会触发请求.

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

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

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

怎么做

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

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

怎么写

直接上代码:

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 submit = () => {
  console.log('submit')
}
const debounceSubmit = debounce(submit, 500)

let btnSubmit = document.getElementById('submit')
btnSubmit.addEventListener('click', () => {
  console.log('click')
  debounceSubmit()
})
复制代码

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

看下效果:

上图中,一开始的几次连续点击,都不会触发 submit ,停止点击后,才触发了一次 submit . 之后两次有一定间隔时间的点击,都触发了 submit.

总结

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




原文地址:访问原文地址
快照地址: 访问文章快照