1.为什么要防抖和节流

  1. 举个简单的例子,很多网站的搜索框需要通过输入文本框的内容实时检索数据。每输入一个字符就会触发一次函数执行,因此函数的执行频率很高,很可能内容还没输入完就已经触发函数执行
  2. 然而实际上我们并不需要这么高频率的执行反馈,它会浪费浏览器性能,甚至可能牵涉后台请求而影响服务器性能;因此就有了使用防抖和节流来进行性能优化
  3. 防抖和节流一般在onresize、mousemove、滚动事件等事件中使用,防止过多的请求造成服务器压力

    2.函数防抖(debounce)

  4. 一个需要频繁触发的函数,在规定时间内只让最后一次生效,前面不生效。也就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

  5. 比如在输入框输入时,要搜索某个字符串,基于性能考虑,肯定不能用户没输入一个字符就发送一次搜索请求,使用的方法就是等待用户停止输入,比如过了500ms用户都没有再输入,那么就搜索此时的字符串,这就是防抖
  6. 代码实现

    1. 短时间内多次触发同个事件,只会执行一次函数。
    2. 函数防抖一般是指对于在事件被触发n秒后再执行的回调,如果在这n秒内又重新被触发,则重新开始计时。
    3. 使用setTimeout函数
      1. function debounce(fn,delay){
      2. var timer = null;
      3. return function(){
      4. clearTimeout(timer)// 清除上一延时器
      5. timer = setTimeout(function(){// 重新设置新的延时器
      6. fn()
      7. },delay)
      8. }
      9. }
      10. var ipt = document.querySelector('input')
      11. ipt.oninput = debounce(function () {
      12. console.log(ipt.value);
      13. }, 1000)
      采用非立即执行方式,确保获取到最新的输入框值,n秒内没有再次输入才会触发函数,否则重新倒计时n秒,直到n秒内没有再次输入的时候才会触发函数执行。

      3.节流(throttle)

  7. 所谓节流,是指频繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数。指连续触发事件但是在 n 秒中只执行一次函数,所以节流稀释了函数执行的频率

  8. 类比到生活中的水龙头,拧紧水龙头到某种程度会发现,每隔一段时间,就会有水滴流出。
  9. 上面输入框例子中防抖的实现是n秒内不再输入则触发函数执行,然而如果我们一直保持n秒内输入,则将永远无法触发函数,如果希望即使用户不停输入,也能够在某个时间间隔反馈(触发函数),因此有了第二种解决思路:节流

使用时间戳实现节流(onscroll事件)

  1. 使用时间戳实现节流(onscroll事件)
  2. fn: 要被节流的函数
  3. delay:规定的时间
  4. function throttle(fn,delay){
  5. var lasttime = 0 ;// 记录上一次触发的时间
  6. // 通过闭包的方式使用lasttime变量,每次都是上次的时间
  7. return function(){
  8. var nowtime = Date.now();
  9. if(nowtime-lasttime>delay){
  10. fn()// 调用函数
  11. lasttime = nowtime; // 同步时间
  12. }
  13. }
  14. }
  15. document.onscroll = throttle(function(){
  16. console.log("scroll事件被触发了"+Date.now());
  17. }
  18. ,1000)
  19. 上方代码设置时间为1s,实现的效果,当滚动屏幕时控制台打印当前时间戳,虽然是一直滚动屏幕,但也是在时间周期1s后才会第二次输出当前时间戳。由此实现了函数的节流。

使用setTimeout实现节流(onmousemove事件)

  1. 使用setTimeout实现节流(onmousemove事件)
  2. function throttle(fn, delay) {
  3. let flag = false
  4. return function () {
  5. if (flag) {
  6. return // 如果flag = false,那就直接不执行下边的代码
  7. }
  8. flag = true // 持续触发的话,flag一直是true,就会停在上边的判断那里
  9. setTimeout(() => {
  10. fn()// 定时器到时间之后,函数就会被执行
  11. flag = false
  12. }, delay)
  13. }
  14. }
  15. var box=document.querySelector('.box')
  16. box.onmousemove = throttle(function (e) {
  17. console.log('onmousemove事件被触发了'+ Date.now());
  18. }, 1000)
  19. 函数执行的前提条件是开关打开,持续触发时,持续关闭开关,等到setTimeout到时间了,再把开关打开,函数就会执行了。

4.防抖常见应用场景

  1. 搜索框搜索输入。只需用户最后一次输入完,再发送请求。
  2. 手机号、邮箱验证输入检测。
  3. 窗口大小Resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。

    5.节流常见应用场景

  4. 滚动监听,返回顶部功能,即监听浏览器滚动事件,返回当前滚动条位置与顶部距离。可以采用节流方式,当滚动条滚动时以n秒的时间间隔获取当前位置与浏览器顶部距离。

  5. 按钮提交事件
  6. 懒加载要监听计算滚动条的位置,使用节流按一定时间的频率获取。

    总结

  7. 防抖和节流都是为了解决频繁触发某个事件造成的性能消耗,在用户体验允许的情况下减少性能浪费。

  8. 函数防抖和节流区别在于
    1. 函数防抖的情况下,函数将一直推迟执行,造成不会被执行的效果;
    2. 函数节流的情况下,函数将每隔 n 秒执行一次
    3. 节流防抖就好比乘电梯,比如delay(等待)是10秒,那么防抖就是电梯每进来一个人就要等10秒再运行,而节流就是电梯保证每10秒可以运行一次
  9. 在项目中,至于选用防抖还是节流来降低性能损耗,可根据项目实际需求而定。