防抖与节流:函数执行频率控制技巧
本文摘要
防抖和节流是控制函数执行频率的两种机制。防抖在事件停止触发后延迟执行回调,适用于等待用户停止操作的场景(如回城技能)。节流throttle则限制函数在固定间隔内只能执行一次(如技能冷却)。文章提供了防抖函数的实现(使用定时器清除重置)和节流函数的三种实现方式:定时器尾触发、时间戳首触发及定时器首触发。核心都是通过管理定时器或时间戳来控制函数执行时机,其中apply确保正确this指向。
概念介绍
防抖(debounce)
防抖机制会在事件触发后延迟执行回调函数。如果在延迟时间内事件再次被触发,则会重新开始计时。只有当事件在指定时间内不再触发时,回调函数才会执行。这种机制常用于需要等待用户停止操作后才执行的场景。
例子:在王者荣耀游戏中,当玩家移动时连续点击回城按钮,移动会中断上次回城并重新计时。只有当玩家停止移动时点击回城,才会完成整个计时过程成功回城。
节流(throttle)
节流机制会限制函数在固定时间间隔内只能执行一次,从而控制函数的执行频率。
例子:游戏技能的冷却机制。技能释放后会进入冷却状态,在冷却时间内无法再次释放,直到冷却时间结束。
防抖函数实现
function debounce(func, delay) {
let timer = null;
return function() {
console.log(this); // this指向DOM元素
let context = this;
let args = arguments;
if(timer) clearTimeout(timer); // 清除已有定时器
timer = setTimeout(() => {
func.apply(context, args); // 使用apply确保正确的this指向
}, delay); // 创建新的定时器
}
}
const gohome = document.querySelector('#gohome');
gohome.addEventListener('click', debounce(function() {
console.log(this); // this指向window
}, 1000));
节流函数实现
定时器实现(尾触发)
function throttleSetTimeout(func, delay) {
let timer = null;
return function() {
if(timer) return; // 如果处于冷却期则直接返回
timer = setTimeout(() => {
func.apply(this, arguments);
timer = null; // 冷却结束
}, delay); // 开始冷却
}
}
定时器首触发实现
function throttleSetTimeout(func, delay) {
let timer = null;
return function() {
if(timer) return; // 如果处于冷却期则直接返回
func.apply(this, arguments); // 立即执行函数
timer = setTimeout(() => {
timer = null; // 冷却结束
}, delay); // 开始冷却
}
}
时间戳实现(首触发)
function throttleTimeStamp(func, delay) {
let lastTime = 0;
return function() {
let now = Date.now();
if(now - lastTime < delay) return; // 检查是否在冷却期内
func.apply(this, arguments); // 立即执行函数
lastTime = Date.now(); // 更新最后执行时间
}
}
作用与优点
节流的作用和优点
节流(Throttle)的作用是限制函数在一定时间内只能执行一次,无论触发频率多高。这在处理高频事件(如滚动、鼠标移动)时非常有用。
优点包括减少不必要的计算和资源消耗,避免性能问题。例如在滚动事件中,节流可以确保函数不会在每次像素滚动时都触发,而是每隔一定时间才执行一次。
防抖的作用和优点
防抖(Debounce)的作用是确保函数在最后一次触发后的一定时间间隔后才执行,如果在这段时间内再次触发,则重新计时。适用于输入框搜索建议等场景。
优点在于避免频繁操作导致的重复执行,节省资源。例如在用户连续输入时,防抖可以确保只在用户停止输入后才发送请求,减少不必要的网络请求。
节流适用于滚动加载、窗口调整等高频事件。防抖适用于搜索框输入、表单验证等需要等待用户停止操作后再处理的场景。理解两者的区别有助于选择合适的技术优化性能。