前言
防抖(Debounce)和节流(Throttle)都是前端性能优化中常用的技术手段,它们的核心目的都是为了控制函数执行的频率,从而减少不必要的资源消耗。具体来说,它们的目标是限制某些高频触发的函数在短时间内被频繁执行,例如窗口调整、滚动事件、输入框搜索建议、鼠标移动等操作。
之所以需要限制函数的执行次数,是因为在某些场景下,用户的行为可能会触发大量重复的函数调用,进而频繁地向后端发起请求。这不仅会加重服务器的负担,还可能导致网络拥堵、响应延迟等问题。同时,前端如果频繁执行复杂计算或操作 DOM,也会造成页面卡顿,影响用户体验。
使用防抖和节流机制可以有效缓解这些问题。防抖的核心思想是,在事件被触发后等待一段时间,若在这段时间内没有再次触发,才真正执行函数;而节流则是确保函数在一定时间间隔内只执行一次,无论触发频率有多高。
通过合理使用这两种技术,可以显著提升应用的性能与响应速度,同时减轻后端服务器的压力,实现更高效的前后端协作。
实现防抖
让我们先来看一个小例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" id="inputA">
<script>
let inputA = document.getElementById('inputA')
inputA.addEventListener('keyup',function(event){
console.log(event.target.value)
})
</script>
</body>
</html>
可以看到,我只是随便输入了几个字母,就输出了这么多次,如果在实际应用中,这个应用的服务器压力会非常大,因此我们需要防抖:在事件被触发后等待一段时间,若在这段时间内没有再次触发,才真正执行函数。
防抖实现的原理
防抖的原理很简单:每当一个指定的事件被触发时(例如用户在输入框中输入内容),都会创建一个新的定时器,并设定一个特定的时间间隔(如300毫秒)。如果在这个时间间隔内,该事件再次被触发(意味着用户又进行了新的输入),则取消之前的定时器,并重新开始计时。这一过程会持续到用户停止输入并且超过了设定的时间间隔后,最后一次设置的定时器才会被执行,从而触发相应的处理逻辑。
让我们试着来写一下防抖的代码:
<script>
let inputA = document.getElementById('inputA')
```
let timer = null; // 将timer变量移至此处,使其不在每次事件触发时都被重新定义
inputA.addEventListener('keyup', function(event){
if(timer !== null){
clearTimeout(timer); // 如果存在旧的定时器,则清除它
}
timer = setTimeout(function(){
console.log(event.target.value);
}, 1000);
});
</script>
可以看到确实减少了次数,但是上面这个代码复用性不好,实际上,一个项目里面有很多需要防抖的地方,我们需要把它封装成一个函数到时候直接复用就行,大大的提升了效率。我们可以用闭包来实现。
<script>
let inputA = document.getElementById('inputA')
function debounce(fn,delay){
let timer = null;
return function(...args) {
if (timer != null) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
inputA.addEventListener('keyup',debounce(function(event){
console.log(event.target.value)
},1000))
</script>
节流的实现原理
节流的原理很简单:每当一个指定的事件被触发时(例如用户滚动页面或调整窗口大小),都会检查上一次执行的时间。如果距离上一次执行已经超过了设定的时间间隔(如 300 毫秒),则执行相应的处理逻辑,并记录当前执行时间;否则,跳过本次触发。这一机制确保了在高频事件触发时,处理函数不会被频繁执行,而是按照设定的时间间隔稳定执行一次。
让我们来用闭包来实现节流
<script>
let inputA = document.getElementById('inputA');
function throttle(fn, delay) {
let lastTime = 0; // 上一次执行的时间戳
return function(...args) {
const now = Date.now();
if (now - lastTime >= delay) {
fn.apply(this, args); // 执行函数
lastTime = now; // 更新上一次执行时间
}
};
}
inputA.addEventListener('keyup', throttle(function(event) {
console.log(event.target.value);
}, 1000)); // 每1000ms内只执行一次
</script>
总结
防抖:在规定时间内,多次触发只响应最后一次。(多次触发,只执行最后一次)
应用场景:
-
输入框搜索建议:当用户输入时,防抖可以用于延迟发送请求,避免频繁请求后端接口。
-
窗口大小调整:当窗口大小调整时,防抖可以用于调整事件触发的频率,避免频繁操作导致页面抖动。
-
按钮防重复点击:当用户频繁点击按钮时,防抖可以用于限制按钮点击的频率,避免重复提交操作。
节流:在规定时间内,多次触发只响应第一次。(规定时间内,只触发一次)
应用场景:
- 页面滚动加载:当用户滚动页面时,节流可以用于限制加载事件的触发频率,避免过多的加载请求。
- 频繁点击按钮:当用户频繁点击按钮时,节流可以用于限制按钮点击的频率,避免过于频繁的操作。