推荐答案
防抖 (Debounce)
概念:防抖是指在事件被触发后,延迟一段时间 wait 再执行回调函数。如果在 wait 时间内再次触发事件,则会重新计时,直到超过 wait 时间后才会执行回调。简单来说,就是将多次连续的操作合并成最后一次操作。
应用场景:
- 输入框实时搜索:用户输入时,避免频繁请求服务器,只有在用户停止输入一段时间后才发送请求。
- 按钮点击:防止用户快速多次点击导致重复提交。
- 窗口resize:调整窗口大小时,避免频繁触发回调,只在调整完成后执行一次。
节流 (Throttle)
概念:节流是指在事件被触发后,在固定时间间隔 interval 内只执行一次回调函数。如果事件在 interval 时间内被多次触发,回调函数只会执行一次。也就是说,它会降低事件触发的频率。
应用场景:
- 鼠标mousemove事件:避免鼠标移动时频繁触发回调,例如:在canvas上绘图、鼠标跟随动画等。
- 页面滚动事件:避免页面滚动时频繁触发回调,例如:实现滚动加载、懒加载等。
- 抢购倒计时:避免用户频繁点击,只允许在时间间隔内触发一次。
区别
| 特性 | 防抖 (Debounce) | 节流 (Throttle) |
|---|---|---|
| 执行时机 | 在事件停止触发后 wait 时间执行一次 |
在时间间隔 interval 内只执行一次 |
| 执行次数 | 多次触发合并成最后一次执行 | 在时间间隔内,只执行一次,无论触发多少次 |
| 目标 | 减少事件触发次数,避免频繁操作,提高性能 | 控制事件触发频率,防止事件触发过于频繁 |
| 关注点 | 事件停止触发后的执行结果 | 事件触发的频率 |
本题详细解读
防抖 (Debounce) 的实现原理及代码示例
防抖的核心在于延迟执行回调函数,并取消之前未执行的计时器。通常我们会使用 setTimeout 和 clearTimeout 来实现。
// www.javascriptcn.com code example
function debounce(func, wait) {
let timeout;
return function(...args) {
const context = this; // 保存this指向
clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
};
}
// 示例
function handleInput() {
console.log('输入处理');
}
const debouncedHandleInput = debounce(handleInput, 300);
// html 示例
// <input type="text" oninput="debouncedHandleInput()" />
在上面的例子中,每次输入框的值发生变化都会调用 debouncedHandleInput 函数。 如果用户在 300ms 内继续输入,之前的定时器会被清除,重新设置新的定时器,只有用户在 300ms 内没有继续输入,定时器才会执行 handleInput 函数。
节流 (Throttle) 的实现原理及代码示例
节流的核心在于在固定时间间隔内只允许执行一次回调函数。我们可以通过使用时间戳或定时器来实现。
时间戳实现
// www.javascriptcn.com code example
function throttle(func, interval) {
let lastTime = 0;
return function(...args) {
const now = Date.now();
const context = this;
if (now - lastTime >= interval) {
func.apply(context, args);
lastTime = now;
}
};
}
// 示例
function handleScroll() {
console.log('滚动事件');
}
const throttledHandleScroll = throttle(handleScroll, 200);
// html 示例
// <div onscroll="throttledHandleScroll()"></div>在上面的时间戳实现方式中, lastTime 记录上一次执行的时间,当当前时间与上次执行时间超过 interval 时,执行回调,并更新 lastTime 。
定时器实现
// www.javascriptcn.com code example
function throttle(func, interval) {
let timeout = null;
return function(...args) {
const context = this;
if(!timeout){
timeout = setTimeout(() =>{
func.apply(context,args);
timeout = null;
},interval)
}
}
}
// 示例
function handleScroll() {
console.log('滚动事件');
}
const throttledHandleScroll = throttle(handleScroll, 200);
// html 示例
// <div onscroll="throttledHandleScroll()"></div>在上面的定时器实现方式中,使用 timeout 来标识是否执行了回调。 如果没有 timeout,设置定时器, 并将 timeout 置为 null,方便下次触发。
注意事项
- 防抖和节流都是为了优化性能,避免频繁操作导致的性能问题,可以根据具体的场景选择合适的方法。
- 在实际使用中,可以根据需要对
wait和interval进行调整,以达到最佳效果。 - 在一些特殊的场景下,防抖和节流可以结合使用,以达到更精确的控制效果。例如,在滚动加载时,可以使用节流来控制滚动事件的触发频率,同时可以使用防抖来控制加载数据的请求。