前言
在面试的时候,防抖&节流被问及到的几率是非常大的,这也算是基础的问题吧。可以体现一个人的技术基础怎么样,所以通常应该会是一面的时候被问到,那么你是怎么回答的呢?或者让你实现你能写出来吗?
正文
什么是防抖?
所谓的防抖,指的就是在触发事件的一个时间段内,只要事件不再触发,才让这个回调函数去执行。所以说,如果在这个时间段里面重复触发事件,那么将会先清除上一次任务或者函数(也可以说是时间),然后重新去开启一个新的任务,当用户结束操作后,如果到了指定的这个时间段,那么就会执行一次这个函数。
所以也可以看成,在过滤用户的操作行为,当用户操作结束后,才去执行函数给予反馈。
防抖的实现
代码语言: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>