防抖(Debouncing)与节流(Throttling)详解及实战案例
在前端开发中,处理高频事件(如窗口大小调整、滚动、键盘输入等)时,为了提高性能并减少不必要的计算或DOM操作,常常采用防抖(Debouncing)和节流(Throttling)两种技术。这两种技术虽然目的相似,但实现方式和应用场景有所不同。
防抖和节流的定义
-
防抖(Debouncing):确保事件处理函数在指定时间间隔内只执行一次。如果在这个时间间隔内事件被再次触发,则重新计时。防抖常用于输入框搜索自动完成、窗口大小调整等场景。即,单位时间内,频繁触发事件,只执行最后一次。
-
节流(Throttling):确保事件处理函数在指定时间间隔内至少执行一次。如果事件在这个时间间隔内被多次触发,则只有第一次或最后一次会被执行。节流常用于滚动事件监听、动画循环等场景。即,单位时间内,频繁触发事件,只执行一次。
防抖使用流程
核心是利用 setTimeout定时器来实现
-
声明定时器变量
-
每次鼠标移动(事件触发)的时候都要先判断是否有定时器,如果有先清除以前的定时器
-
如果没有定时器,则开启定时器,存入到定时器变量里面
-
定时器里面写函数调用
防抖函数的实现
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout); // 清除之前的定时器
timeout = setTimeout(() => {
func.apply(context, args); // 使用apply保持this上下文和参数传递
}, wait);
};
}
使用案例
//html部分
<button id="myButton">点击我,但别太频繁!</button>
<div id="result"></div>
//javascript部分
function doSomething() {
const resultDiv = document.getElementById('result');
resultDiv.textContent = '按钮被点击了(防抖生效)!';
}
// 获取按钮并添加点击事件监听器,使用防抖函数
const button = document.getElementById('myButton');
const debouncedClick = debounce(doSomething, 500); // 设置防抖时间为500毫秒
button.addEventListener('click', debouncedClick);
在这个例子中,当用户频繁点击按钮时,doSomething 函数不会立即执行。只有当用户在最后一次点击后等待了500毫秒没有再次点击时,doSomething 函数才会执行,更新页面上的文本内容。这样,即使用户快速连续点击按钮,页面上显示的文本也不会频繁地更新,从而达到了防抖的效果。
节流使用流程
核心是利用定时器(setTimeout)来实现
-
声明一个定时器变量
-
当鼠标每次滑动都先判断是否有定时器了,如果有定时器则不开启新定时器
-
如果没有定时器则开启定时器,记得存到变量里面
-
定时器里面调用执行的函数
-
定时器里面要把定时器清空
节流函数的实现
function throttle(func, limit) {
let lastFunc;
let lastRan;
return function() {
const context = this;
const args = arguments;
if (!lastRan) {
func.apply(context, args);
lastRan = Date.now();
} else {
clearTimeout(lastFunc);
lastFunc = setTimeout(function() {
if ((Date.now() - lastRan) >= limit) {
func.apply(context, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
};
}
使用案列
// 假设的操作函数
function handleScroll() {
console.log('滚动事件被处理了(节流生效)!', new Date().toLocaleTimeString());
}
// 使用节流函数包装handleScroll
const throttledScroll = throttle(handleScroll, 500);
// 添加滚动事件监听器,并使用节流函数
window.addEventListener('scroll', throttledScroll);
在这个例子中,当用户滚动页面时,handleScroll 函数不会立即执行。相反,它会在每次滚动事件触发时检查距离上次执行的时间是否已经超过500毫秒。如果是,则执行该函数;如果不是,则等待直到满足条件再执行。这样,即使在用户快速滚动页面时,handleScroll 函数也不会被过度调用,从而实现了节流的效果。
使用lodash来解决防抖和节流案列:
案例一:输入框防抖
场景:用户在搜索框输入时,不希望每次按键都触发搜索请求,而是等待用户停止输入一段时间后再进行搜索。
代码示例(使用lodash):
import _ from 'lodash';
const search = _.debounce(function(query) {
console.log('Searching for:', query);
// 这里可以放置搜索请求的代码
}, 300);
// 绑定到输入框的input事件
document.querySelector('#searchBox').addEventListener('input', function(e) {
search(e.target.value);
});
案例二:滚动节流
场景:在滚动事件中,不需要每次滚动都执行某些操作(如计算可视区域元素),而是希望在滚动过程中定期执行。
代码示例(使用lodash):
import _ from 'lodash';
const throttledScrollHandler = _.throttle(function() {
console.log('Scroll event handler called');
// 可以在这里执行一些操作,如计算可视区域内的元素
}, 1000);
window.addEventListener('scroll', throttledScrollHandler);
使用场景
-
防抖(Debouncing):
- 搜索框输入时减少请求次数。
- 窗口大小调整时延迟执行重排或重绘相关的代码。
- 按钮点击后,防止因双击而重复执行。
-
节流(Throttling):
- 滚动事件监听,减少滚动过程中的计算量。
- 游戏中的动画循环,控制更新频率。
- 实时搜索结果的展示,控制请求频率。
Lodash是一个一致性、模块化、高性能的JavaScript实用工具库。它内部封装了诸多对字符串、数组、对象等常见数据类型的处理函数,通过降低这些常见数据类型的使用难度,从而让JavaScript编程变得更加简单和高效。