防抖
“等电梯模式”描述的是防抖(Debouncing)的概念,这种模式意味着在某个动作结束后的固定时间内,如果没有再次触发该动作,才会执行相应的函数。可以类比为按下电梯按钮,如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,如果在设定的时间内没有人再次按下按钮,电梯就会开始运行。
防抖函数实现
/**
* 防抖函数
* 在一段时间内连续触发事件,只在最后一次触发事件后的指定延迟时间后执行一次函数
*
* @param {Function} fn - 需要防抖处理的函数
* @param {number} delay - 延迟时间,单位为毫秒
* @returns {Function} 防抖处理后的函数
*/
function debounce(fn, delay) {
let timeout;
return function (...args) {
// 清除之前的定时器
clearTimeout(timeout);
// 设置新的定时器
timeout = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
解释
- 变量
timeout
:用于存储定时器的标识。 - 返回函数:每次调用时都会清除之前的定时器并设置一个新的定时器,只有在一定时间内没有新的调用时,原函数才会执行。
示例用法
const searchInput = document.getElementById('searchInput');
const handleSearch = debounce(() => {
console.log('Search triggered');
}, 300);
searchInput.addEventListener('input', handleSearch);
在这个示例中,handleSearch
只有在输入停止后的300毫秒后才会执行,即使在输入过程中有多次事件触发。
节流
类比分析
- 地铁模式:地铁列车按固定的时间间隔发车,不会因为乘客数量的变化而改变发车时间。
- 节流:函数在固定的时间间隔内最多执行一次,不会因为事件触发频率的变化而改变执行频率。
节流实现
/**
* 节流
* 连续触发事件但是在n秒中只执行一次函数。节流会稀释函数的执行频率。
*
* 单位时间内,操作n次,选中第一次
*
* 特点:只执行一次
* 设置标识位,看能不能触发事件
*
*/
function throttle(fn, delay) {
let canRun = true;
return function () {
if (!canRun) return;
canRun = false;
setTimeout(() => {
fn.apply(this, arguments);
canRun = true;
}, delay);
};
}
解释
- 变量
canRun
: 初始值为true
,表示可以执行函数。 - 返回函数: 检查
canRun
是否为true
,如果是则执行函数,并将canRun
设为false
。 setTimeout
回调: 在delay
毫秒后,执行传入的函数fn
,然后将canRun
设为true
,以便下次可以执行。
示例用法
const handleScroll = throttle(() => {
console.log('Scroll event handler called');
}, 200);
window.addEventListener('scroll', handleScroll);
在这个示例中,滚动事件的处理函数 handleScroll
会在每200毫秒内最多执行一次,即使滚动事件频繁触发。
区分防抖与节流
- 防抖(Debouncing) :在连续触发事件结束后的固定时间内只执行一次函数。
- 节流(Throttling) :在规定的时间间隔内最多执行一次函数。
例如,都设置时间频率为500ms,在2秒时间内,频繁触发函数,节流
,每隔 500ms 就执行一次。防抖
,则不管调动多少次方法,在2s后,只会执行一次
如下图所示:
应用场景
防抖在连续的事件,只需触发一次回调的场景有:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小
resize
。只需窗口调整完成后,计算窗口大小。防止重复渲染。
节流在间隔一段时间执行一次回调的场景有:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能