在JavaScript中,防抖(debounce)和节流(throttle)是两种常用的技术,用于限制函数的执行频率,特别是在处理高频事件(如窗口的resize、scroll,输入框的keyup、mousedown等)时非常有用。
防抖(debounce)
防抖的基本思想是将多次执行变为最后一次执行。也就是说,在事件被触发后n秒内函数只能执行一次,如果在这n秒内又被重新触发,那么会重新计算执行时间。这就像是在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,它一定是当你结束输入一段时间之后才会触发。
防抖的实现过程大致如下:当事件触发时,相应的函数并不会立即被触发,而是会等待一定的时间;当事件密集触发时,函数的触发会被频繁的推迟;只有等待了一段时间也没有事件触发,才会真正的执行响应函数。
节流(throttle)
节流的基本思想是将多次执行变成每隔一段时间执行。也就是说,预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。这就像是在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。
在实现上,节流通常使用时间戳和定时器来实现。当事件触发时,会检查当前时间与上次执行函数的时间差,如果小于设定的执行周期,则不执行函数;如果大于或等于执行周期,则执行函数并更新上次执行时间。此外,还可以使用定时器来定期执行函数,但需要注意在适当的时候清除定时器以避免内存泄漏。
实例说明
我这里分别举一个防抖(debounce)和节流(throttle)的例子来说明它们的用法和效果。
防抖(debounce)
假设我们有一个搜索框,用户可以在其中输入文字进行搜索。我们不希望用户每输入一个字符就发送一次搜索请求,因为这样会造成大量的不必要的请求和服务器负担。我们可以使用防抖技术来解决这个问题。
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
}
const searchInput = document.querySelector('#searchInput');
searchInput.addEventListener('input', debounce(function(event) {
// 这里发送搜索请求
console.log('执行搜索:', event.target.value);
}, 500));
在这个例子中,debounce
函数返回一个新的函数,这个新函数在每次被调用时都会取消之前的定时器并设置一个新的定时器。因此,只有在停止输入一段时间(这里是500毫秒)后,才会执行搜索函数。
节流(throttle)
假设我们有一个滚动事件监听器,当用户滚动页面时,我们需要执行一些操作(比如更新导航栏的位置)。但是,滚动事件会非常频繁地触发,如果我们直接在每个事件触发时都执行操作,会造成页面的卡顿。我们可以使用节流技术来解决这个问题。
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
window.addEventListener('scroll', throttle(function() {
// 这里执行一些操作
console.log('页面滚动了');
}, 200));
在这个例子中,throttle
函数返回一个新的函数,这个新函数在每次被调用时都会检查一个标志位 inThrottle
。如果 inThrottle
为 false
,则执行函数并将 inThrottle
设置为 true
,然后设置一个定时器在一段时间后(这里是200毫秒)将 inThrottle
设置回 false
。因此,只有在每个200毫秒的时间段内第一次触发滚动事件时,才会执行操作函数。