防抖和节流的作用都是为了防止函数多次调用。
一、防抖
触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间
举例:在百度搜索时,每次输入之后都会有相关联的信息弹出,但是不可能用户输入框内容一改变就触发的,一定是当你结束输入一段时间之后才会触发。
我们先来看一个袖珍版的防抖理解一下防抖的实现:
// fn 是用户传入需要防抖的函数
// delay 是等待时间
function debounce(fn, delay = 500) {
// timer 是闭包中
let timer = null
// 这里返回的函数是每次用户实际调用的防抖函数
// 如果已经设定过定时器了就清空上一次的定时器
// 开始一个新的定时器,延迟执行用户传入的方法
return function () {
if(timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
// 不难看出如果用户调用该函数的间隔小于 delay 的情况下,上一次的时间还未到就被清除了,并不会执行函数
这个防抖只能在最后调用,有缺陷。防抖函数分为:【延迟执行】的防抖函数和【立即执行】的防抖函数。
下面我们来实现一个带有立即执行选项的防抖函数
// 这个是用来获取当前时间戳的
function now() {
return +new Date()
}
/**
* 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
*
* @param {function} func 回调函数
* @param {number} wait 表示时间窗口的间隔
* @param {boolean} immediate 设置为ture时,是否立即调用函数
* @return {function} 返回客户调用函数
*/
function debounce (func, wait = 50, immediate = true) {
let timer, context, args
// 延迟执行函数
const later = () => setTimeout(() => {
// 延迟函数执行完毕,清空缓存的定时器序号
timer = null
// 延迟执行的情况下,函数会在延迟函数中执行
// 使用到之前缓存的参数和上下文
if (!immediate) {
func.apply(context, args)
context = args = null
}
}, wait)
// 这里返回的函数是每次实际调用的函数
return function(...params) {
// 如果没有创建延迟执行函数(later),就创建一个
if (!timer) {
timer = later()
// 如果是立即执行,调用函数
// 否则缓存参数和调用上下文
if (immediate) {
func.apply(this, params)
} else {
context = this
args = params
}
// 如果已有延迟执行函数(later),调用的时候清除原来的并重新设定一个
// 这样做延迟函数会重新计时
} else {
clearTimeout(timer)
timer = later()
}
}
}
适用场景:
1.按钮提交场景:防止多次提交按钮,只执行最后提交的一次。
2.服务端验证场景:表单验证需要服务端配合,只执行一段连续的输入事件的最后一次,还有搜索联想词功能等。
// 函数防抖
_debounce (wait = 300) {
clearTimeout(this.timer)
this.timer = setTimeout(() => {
// 响应操作
}, wait)
}
二、节流
高频事件触发,在 n 秒内只会执行一次,所以节流会稀释函数的执行效率。
举例:在滚动事件中会发起网络请求,但是我们不希望用户在滚动过程中一直发起请求,而是每隔一段时间发起一次。
// func 是⽤户传⼊需要防抖的函数
// delay 是等待时间
function throottle(fn, delay = 100) {
let timer = null
return function () {
if (timer) {
return
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
setInterval(
throttle(() => {
console.log(1)
}, 500),
500
)
适用场景:
1.拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
2.缩放场景:监控浏览器 resize
3.动画场景:避免短时间内多次触发动画引起性能问题
三、防抖与节流的区别
防抖是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。