在之前我写的图片懒加载中提到过防抖节流,随着我更深入的学习发现防抖节流中居然还包含了那么多细节,本文我将以输入框为例给大家讲解其中的奥秘。
防抖节流的意义
通常情况下,输入框都是通过添加一个keyup
事件来检测用户输入的内容来实现响应。在没有防抖节流的情况下用户每次按下键盘都会触发事件向服务器发送请求,这不仅容易造成界面响应变慢,也容易出现卡顿,同时也会造成服务器压力过大崩溃的情况。
这是百度搜索的输入框,我发现其中主要使用的还是防抖,在我每一次输入完之后才开始响应。为什么使用防抖比较合适,在下文中我会详细讲解。
案例代码html模块
js
<div class="row">
<div>
没有节流的input<input type="text" id="inputa">
</div>
<div>
防抖后的input<input type="text" id="inputb">
</div>
<div>
节流后的input<input type="text" id="inputc">
</div>
</div>
防抖(Debounce)
原理与目的
防抖技术的核心在于确保一个函数在一段时间内频繁触发后,只执行最后一次。这对于减少不必要的网络请求、避免UI重绘过于频繁非常有效。比如,在输入框中输入关键词时,我们希望用户停止输入一段时间后再发送请求,而不是每次按键都发送请求。
实现思路
- 闭包:利用闭包保存上一次触发的时间戳和定时器引用。
- 判断与清除定时器:每次触发时,检查是否有未执行完的定时器,如果有,则清除并重新计时。
简单来说每一次敲击键盘都会触发计时器,如果在delay
时间内再次触发,其计时器将会被清除,然后重新计时,直到超过delay
使得func(args)
执行。如果第一次超过delay
时间,再次继续输入该机制依然有效,会在第二次输入超过delay
时间后重新执行处理函数。这就是百度输入框使用的方法,输入结束之后发送请求给服务器。(ajax是对keyup的处理函数。)
示例代码
javascript
const inputb = document.getElementById('inputb');
//耗时耗性能的任务=>promise 包一下
const ajax = (content) => {
console.log(`ajax request ${content}`);
}
const debounce = (func, delay) => {
let timer=null;
return (args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func(args);
}, delay)
}
}
let debouncedFunc = debounce(ajax, 1000);
inputb.addEventListener('keyup', (e) => {
let value = e.target.value;
debouncedFunc(value);
})
效果展示
节流(Throttle)
原理与目的
与防抖不同,节流保证一个函数在规定时间内至少执行一次,且无论在这段时间内触发多少次,都只执行一次。这适用于那些需要限制执行频率但又不能完全忽视连续触发的场景,如滚动事件监听。
实现思路
- 闭包:同样利用闭包存储上一次执行的时间戳。
- 判断执行时机:每次触发时,比较当前时间和上一次执行时间,如果超过了指定间隔,则执行函数,并更新上一次执行时间。
简单来说就是当keyup一直在触发时,为实现处理函数每个delay
时间执行一次,那就要使得处理函数在刚开始执行一次,记录下时间然后判断,当现在时间达到delay
时执行处理函数并更新时间。那么似乎不用处理没有达到delay
的情况,但是这样的话只有keyup一直触发的时候才会让处理函数执行,当keyup停止触发无法保证在输入完之后处理函数最后执行一次。那么在小于delay
的时间段内不影响节流的机制又保证最后一次触发处理函数,就需要在keyup一直触发时让里面的计时器产生又再下一次触发keyup时清除,当keyup停止触发时,计时器不再清除,delay
时间后触发最后一次处理函数。
示例代码
javascript
const inputc = document.getElementById('inputc');
//耗时耗性能的任务=>promise 包一下
const ajax = (content) => {
console.log(`ajax request ${content}`);
}
//节流功能
//定义的时刻
const throttle = (func, delay) => {
//last 上一次是什么时候执行的
//deferTimer 定时器id
let last, deferTimer;//自由变量
//func,delay
//才是事件的处理函数
//定义时,生成时 func,delay func调用时能找到闭包中的自由变量
return (args) => {
//当前时间,隐式类型转换
let now = +new Date();
if (last && now < last + delay) {
clearTimeout(deferTimer);
deferTimer = setTimeout(() => {
last = now;
func(args);
}, delay)
} else {
//再次来到这个地方
last = now//第一时间
func(args)//先执行一次
}
}
}
inputa.addEventListener('keyup', (e) => {
ajax(e.target.value);
})
let throttledFunc = throttle(ajax, 1000);
性能优化与用户体验
无论是防抖还是节流,都能显著降低客户端与服务器间的通信频率,减轻服务器压力,同时减少不必要的DOM操作或计算,从而提升应用的响应速度和整体性能。在用户界面交互频繁的场景下,合理运用这些技术,可以大幅提升用户体验,减少因频繁操作导致的卡顿现象。
综上所述,防抖和节流是前端开发中不可或缺的性能优化手段,它们通过对函数执行时机的精确控制,有效解决了高频率事件处理中的性能瓶颈,是构建高性能Web应用的重要工具。