常问面试题,防抖&节流的解答和实现

2022-09-26 11:09:09 浏览数 (1)

前言

在面试的时候,防抖&节流被问及到的几率是非常大的,这也算是基础的问题吧。可以体现一个人的技术基础怎么样,所以通常应该会是一面的时候被问到,那么你是怎么回答的呢?或者让你实现你能写出来吗?

正文

什么是防抖?

所谓的防抖,指的就是在触发事件的一个时间段内,只要事件不再触发,才让这个回调函数去执行。所以说,如果在这个时间段里面重复触发事件,那么将会先清除上一次任务或者函数(也可以说是时间),然后重新去开启一个新的任务,当用户结束操作后,如果到了指定的这个时间段,那么就会执行一次这个函数。

所以也可以看成,在过滤用户的操作行为,当用户操作结束后,才去执行函数给予反馈。

防抖的实现

代码语言:javascript复制
function debounce (fn, wait) {
  const timer = null
  return function (...agrs) {
    clearTimeout(timer)
    timer = setTimeout(() => fn.apply(this, agrs), wait)
  }
}

通过以上代码可以看到,在绑定事件函数的时候,我们执行debounce函数会传入一个参数和一个等待时间。然后内部还会返回一个函数,这个函数会通过事件执行,函数里面会接受到所有的参数args(是一个数组),每次执行函数前都会清理上一次的回调,然后开启一个新的回调。所以是通过定时器做的一个延迟执行,在定时器执行的时候就回调了我们业务逻辑,并且为了保证this的指向,使用了apply方法做了this的指向重置,这样一来就实现了防抖效果。以下是运用场景的一个demo

运用场景,示例:

代码语言:javascript复制
<template>
  <input type="text" v-model="name" @input="debounce(cb, 1000)" />
</template>

<script>
  export default {
    data () {
        return {
          name: ''
        }
      },
    methods: {
      debounce (fn, wait) {
        const timer = null
        return function (...agrs) {
          clearTimeout(timer)
          setTimeout(() => fn.apply(this, agrs), wait)
        }
      },
      cb (e) {
        console.log(e, this.name)
        // 这里可以发送请求或者做一些其它处理     
      }
    }  
  }
</script>

什么是节流?

所谓的节流,指的是连续触发的事件内,在一个时间段只执行一次函数。就是说,节流是为了去稀释函数在事件内的执行频率。

所以可以看成,用户的不断操作在触发这个事件,但是函数的执行是让它在一个时间段中只执行一次,这样就可以让函数的执行频率降低到一个时间维度,所以就得到了节制流量的产生作用。

节流的实现

节流一般有两种方式实现,一种是时间戳的方式,另一种是定时器的方式。

时间戳的实现方式

代码语言:javascript复制
function throttle(fn, wait) {
  let previous = 0
  return function (...args) {
    const now = Date.now()
    if ((now - previous) > wait) {
      fn.apply(this, args)
      previous = now
    }
  }
}

定时器的实现方式

代码语言:javascript复制
function throttle (fn, wait) {
  let timer = null
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null
        fn.apply(this, args)
      }, wait)
    }
  }
}

以上就是两种实现方式:

第一种是使用时间戳计算得出有没有到指定时间,如果到了我们指定的执行时间,那么将会执行一次函数,并重置记录这一次的执行时间,否则将会等待到达时间才执行函数。

时间的计算公式:

现在时间 - 上一次执行函数时间 > 指定的时间 = true 将会执行一次函数

第二种是使用的定时器延迟执行,并通过开关来控制避免多次执行定时器,造成定时器的累积而变混乱。

所以开关的作用就是让定时器执行完当前这一个,才能开始下一个定时器的执行,这样就能控制住一个指定的时间段执行一次函数。

运用场景,示例:

代码语言:javascript复制
<template>
  <div stype="padding: 10000px 0;"></div>
</template>

<script>
    export default {
      methods: {
        throttle(fn, wait) {
          let timer = null
          return function (...args) {
            if (!timer) {
              timer = setTimeout(() => {
                timer = null
                fn.apply(this, args)
              }, wait)
            }
          }
        },
        scrollCallback (e) {
          console.log(e)
          // 这里就可以去做一些处理
        }
      },
      mounted () {
        const evFn = this.throttle(this.scrollCallback, 1000)
        window.addEventListener('scroll', evFn)
        this.$once('hook:beforeDestory', () => {
          window.removeEventListener('scroll', evFn)
        })
      }      
    }
</script>

0 人点赞