防抖函数(Debounce)
防抖函数的概念及应用场景
防抖函数是一种用于控制函数执行频率的优化技术。
在前端开发中,我们经常会遇到一些频繁触发的事件,如
- 输入框输入
- 按钮点击
- 窗口大小调整
- ...
如果不对这些事件的处理函数进行优化,可能会导致大量不必要的计算和资源消耗,甚至影响页面性能。
防抖函数的作用就是确保在一定时间间隔内,函数只执行一次。
如果在这个时间间隔内再次触发函数调用,则重新计时。
比如在横竖屏切换的应用中 , 就需要使用防抖函数实现立即刷新适配 倔友可以移步我的这篇文章 ,一探究竟 ~
探索CSS响应式设计:从原理到实战大家好 ,我是一名在校大二学生 , 今天,我们探索一下CSS响应式设计中的一些核心要点 - 掘金 (juejin.cn))
防抖函数的实现思路
- 使用一个变量(通常为
timeoutId)来存储定时器的 ID。 - 在每次函数调用时,清除之前的定时器(如果存在),以防止上一次的定时器执行函数。
- 设置一个新的定时器,当定时器到期时,执行目标函数。
基础防抖函数实现代码示例
function debounce(func, delay) {
let timeoutId;
return function (...args) {
// 清除之前的定时器
if (timeoutId) {
clearTimeout(timeoutId);
}
// 设置一个新的定时器
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
// 测试代码
function onInput() {
console.log('Input event triggered:', Date.now());
}
const debouncedOnInput = debounce(onInput, 1000);
// 模拟输入事件
setInterval(debouncedOnInput, 200); // 每200毫秒触发一次输入事件
在上述代码中,debounce函数接受一个函数func和一个延迟时间delay作为参数。
它返回一个新的函数,当新函数被调用时,会先清除之前的定时器(如果有),然后设置一个新的定时器,在延迟delay毫秒后执行func函数。
这样,在频繁调用新函数时,只有在最后一次调用后的delay毫秒后,func函数才会真正执行。
立即执行选项的添加
有时我们希望在首次调用防抖函数时立即执行函数,而不是等待延迟时间。
为此,我们可以为防抖函数添加一个immediate选项,用于控制函数是否在首次调用时立即执行。
function debounce(func, delay, immediate = false) {
let timeoutId;
return function (...args) {
const callNow = immediate &&!timeoutId;
// 清除之前的定时器
if (timeoutId) {
clearTimeout(timeoutId);
}
// 设置一个新的定时器
timeoutId = setTimeout(() => {
timeoutId = null;
if (!immediate) {
func.apply(this, args);
}
}, delay);
if (callNow) {
func.apply(this, args);
}
};
}
// 测试代码
function onInput() {
console.log('Input event triggered:', Date.now());
}
const debouncedOnInput = debounce(onInput, 1000, true);
// 模拟输入事件
setInterval(debouncedOnInput, 200); // 每200毫秒触发一次输入事件
在这个扩展后的debounce函数中,当immediate为true且timeoutId不存在时(即首次调用),会立即执行函数。
然后再设置定时器,在延迟时间后,如果immediate为false,则再次执行函数。
防抖函数的实际应用场景
输入框输入事件:在用户输入时,防抖函数可以限制输入事件处理函数的执行频率,从而减少不必要的请求或计算。
例如,实时搜索功能中,当用户输入关键字时,我们可以使用防抖函数来延迟发送搜索请求,直到用户停止输入一段时间后再执行搜索操作,避免频繁请求服务器。
按钮点击事件:在用户频繁点击按钮时,防抖函数可以限制点击事件处理函数的执行频率,从而避免重复操作。
比如提交表单按钮,防止用户多次快速点击导致重复提交数据。
窗口调整大小事件:在用户调整浏览器窗口大小时,防抖函数可以限制调整大小事件处理函数的执行频率,从而避免频繁的布局重绘。
因为窗口大小调整可能会触发大量的计算和重绘操作,使用防抖函数可以优化性能。
节流函数(Throttle)
节流函数的概念及应用场景
节流函数同样用于限制函数的执行频率,但它确保在一段时间内,无论触发多少次事件,函数都只执行一次。
在前端开发中,对于一些高频率触发的事件,如onresize、scroll、mousemove等,如果不加以限制,可能会导致浏览器性能问题。
节流函数通过限制函数的执行频率,有效解决了这个问题。它适用于以下场景:
页面滚动和大小调整
当页面滚动或窗口大小调整时,可能需要执行某些操作,如懒加载数据或调整布局。通过节流函数,可以确保这些操作不会过于频繁地执行。
高频率的事件处理
如按钮被高频点击、游戏中的技能冷却等,通过节流函数可以限制这些操作的执行频率。
DOM操作和资源加载
在高频事件触发时进行DOM操作或资源加载,通过节流函数可以减少不必要的计算和资源消耗。
节流函数的实现方式
节流函数常见的实现方式有时间戳方案和定时器方案。
时间戳方案实现代码示例
function throttle(fn, wait) {
let lastTime = 0;
return function () {
const now = new Date().getTime();
if (now - lastTime > wait) {
fn.apply(this, arguments);
lastTime = now;
}
};
}
在这个时间戳方案的节流函数中,throttle函数接受一个要节流的函数fn和一个等待时间wait(单位毫秒)。
它返回一个新的函数,在每次调用新函数时,会获取当前时间now,然后与上次执行时间lastTime进行比较。如果时间差大于等待时间wait,则执行原始函数fn,并更新lastTime为当前时间。否则,忽略此次调用。
定时器方案实现代码示例
function throttle(fn, wait) {
let timer = null;
return function () {
if (!timer) {
fn.apply(this, arguments);
timer = setTimeout(() => {
timer = null;
}, wait);
}
};
}
在定时器方案的节流函数中,throttle函数同样接受fn和wait参数。当新函数被调用时,如果定时器timer不存在(即当前没有正在等待执行的定时器),则立即执行fn函数,并设置一个定时器,在wait毫秒后清除定时器(即将timer设置为null)。
这样,在定时器未到期前,再次调用新函数时,由于timer不为null,函数将不会被执行,从而实现了节流的效果。
节流函数与防抖函数的对比
防抖函数和节流函数都用于控制函数的执行频率,但它们的触发时机有所不同。
防抖函数在事件触发后等待一段时间,如果在这段时间内没有再次触发事件,则执行函数;如果再次触发事件,则重新计时。
而节流函数在规定的时间间隔内,无论事件触发多少次,函数只会执行一次。
例如在页面滚动事件中:
如果使用防抖函数,只有在用户停止滚动一段时间后才会执行相应操作;
如果使用节流函数,则会按照固定的时间间隔执行操作,无论用户是否在持续滚动。
在实际应用中,需要根据具体需求选择合适的函数来优化性能。