前言:防抖(Debounce)和节流(Throttle)是两种在前端开发中常用的优化技术,它们主要用于处理频繁触发的事件,以减少不必要的计算和提升应用性能。下面我将详细讲解这两种技术的概念、工作原理和区别。
防抖
概念
防抖技术通过延迟执行来避免频繁操作。具体来说,当事件被触发时,防抖函数会设置一个延迟计时器。如果在延迟时间内再次触发事件,计时器会重置。只有在延迟时间过后没有新的事件触发时,才执行目标函数。
以大家都熟悉的王者荣耀举例,防抖就像是点击回城时的读秒行为,在倒计时期间再次点击回城将会重新读秒,只有在读秒期间没有进行其他操作才会执行回城操作也就是成功返回泉水。
工作原理
- 用户需要触发事件
- 防抖函数设置一个计时器,等待指定的延迟时间
- 如果在延迟时间内再次触发事件,则计时器被删除并重新设置
- 如果延迟时间内没有触发新事件,则计时器到时后执行目标函数
代码解析
function debounce(func, delay) {
let timerId;
return function (...args) {
if (timerId) clearTimeout(timerId);
timerId = setTimeout(() => func.apply(this, args), delay);
};
}
不难看出防抖函数接收一个要执行的目标函数以及延迟时间作为参数。函数内部,我们声明了一个变量 timerId
,它将被用来存储一个计时器的ID。之后返回一个新的匿名函数,这个匿名函数可以接收任意数量的参数(通过 ...args
语法)。当返回的匿名函数被调用时,首先会检查 timerId
是否存在,如果存在,则使用 clearTimeout
清除之前的计时器,这一步是为了防止之前的延迟执行被触发。然后使用 setTimeout
设置一个新的计时器,当延迟时间过去后,func
函数将被执行。apply
方法被用来调用 func
函数,并将 this
和传入的参数(args
)传递给它。
有些小伙伴可能会问了:apply的作用是什么??为什么用它来调用func函数呢??
我先简单介绍一下apply方法吧 :在JavaScript中,
apply
方法被用于调用一个对象的一个方法,用另一个对象替换当前对象。apply
方法可以用来指定函数运行时的this
上下文,并且可以传入一个数组(或类数组对象)作为参数。在防抖节流中使用apply的原因就是以下两点啦~
改变
this
上下文: 当你使用事件处理器或某些内置函数时,this
的值可能会被设置为你绑定的元素或undefined
(在严格模式下)。通过使用apply
,你可以显式地指定this
的值,使得函数可以在正确的上下文中运行。传递参数:
apply
允许你传递一个数组作为参数给函数,这在处理事件监听器中的参数时特别有用。由于事件对象通常作为第一个参数传递给事件处理函数,使用apply
可以确保原始的函数接收正确的参数。
使用场景
- 输入框搜索:用户输入时,不立即执行搜索,而是在用户停止输入一段时间后才执行。
- 窗口大小调整(resize):只在用户调整完毕后执行,而不是在调整过程中不断执行。
- 表单验证:在用户停止输入后进行验证,而不是每次按键都进行验证。
节流
概念
节流技术则是限制函数的执行频率,在固定的时间间隔内只执行一次函数,即使事件被多次触发。
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
工作原理
- 用户触发事件。
- 节流函数检查上一次执行时间。
- 如果当前时间与上次执行时间的差大于设定的等待时间,则执行目标函数并更新上次执行时间。
- 如果当前时间与上次执行时间的差小于等待时间,则忽略此次触发。
代码解析
function throttle(func, wait) {
let lastTime = 0;
return function () {
const now = new Date().getTime();
if (now - lastTime > wait) {
func.apply(this, arguments);
lastTime = now;
}
};
}
看上述代码,我们发现它接收要执行的目标函数与两次执行之间的等待时间(以毫秒为单位)作为参数。在函数内部我们声明了lastTime用来存储上一次执行目标函数的时间。之后返回一个匿名函数,每次事件触发都会执行匿名函数。在匿名函数中我们获取了当前时间now,接着检查当前时间与上一次执行时间的差值是否大于等待时间 wait
。如果是,则执行 func
函数,并更新 lastTime
为当前时间。如果当前时间与上一次执行时间的差值小于 wait
,则函数不执行,从而实现了节流效果。
使用场景
- 页面滚动(scroll):在滚动过程中,每隔一定时间更新页面状态,而不是每次滚动都更新。
- 按钮点击:防止用户连续快速点击按钮导致的重复提交。
- 游戏动画:控制技能释放频率,防止过于频繁的技能释放。
防抖与节流的区别
- 执行时机: 防抖在事件停止触发后才执行一次,而节流在固定时间间隔内执行一次。
- 适用场景: 防抖适用于需要延迟执行的场景,节流适用于需要控制执行频率的场景。
- 效果: 防抖可以避免不必要的函数执行,节流可以保证函数按设定的频率执行。