欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > JS 防抖与节流

JS 防抖与节流

2025/3/31 13:51:54 来源:https://blog.csdn.net/weixin_62971133/article/details/146509037  浏览:    关键词:JS 防抖与节流

防抖

        核心思想:延迟执行,只有在事件触发的频率降低到一定程度后才会执行,而且如果事件持续触发,之前地所有执行都会被取消。

        有的操作是高频触发的,但是其实只需要一次触发。比如短时间内多次缩放页面resize,我们不应该每次缩放都去执行操作,应该只做一次。再比如监听输入框的输入,不应每次输入框内容变化都触发监听,应该是用户完成一段输入后再进行触发。

        防抖就是为了避免事件重复触发。

        具体步骤: 每当事件触发 就 开一个定时器 。如果再次触发,清除之前该事件的定时器,重设一个。直到定时器到时,触发操作。

示例:

function debounce(func, delay = 300) {let timer;// 返回一个新的函数,该函数在被调用时会延迟执行 funcreturn function(...args) {// 保存当前 this 上下文(确保 func 的 this 正确)const context = this;// 清除之前的定时器,重置为最新触发if (timer) clearTimeout(timer);// 设置新的定时器,延迟执行目标函数timer = setTimeout(() => {func.apply(context, args); // 使用 apply 传递 this 和参数}, delay);};
}// 使用示例:输入框搜索防抖
const input = document.querySelector('input');
input.addEventListener('input', debounce((e) => {console.log('搜索内容:', e.target.value);
}, 500));

防抖的变种:立即执行

在某些情况下,我们希望在事件第一次触发时立即执行函数,之后再按照防抖的规则进行处理。可以通过增加一个参数来实现这个功能:

function debounce(func, delay = 300, immediate = false) {let timer;return function (...args) {const context = this;const isFirstCall = !timer;// 清除之前的定时器clearTimeout(timer);if (immediate && isFirstCall) {// 第一次触发且设置了立即执行,则立即执行函数func.apply(context, args);}// 设置新的定时器timer = setTimeout(() => {timer = null;if (!immediate) {// 如果没有设置立即执行,则在延迟时间后执行函数func.apply(context, args);}}, delay);};
}// 使用示例
function clickHandler() {console.log('按钮被点击');
}const button = document.getElementById('myButton');
// 对 clickHandler 函数进行防抖处理,延迟时间为 1000 毫秒,立即执行
button.addEventListener('click', debounce(clickHandler, 1000, true));

节流

        防抖存在的问题:事件会一直等到用户完成操作后一段时间在操作,如果一直操作,会一直不触发。比如说是一个按钮,点击就发送请求,如果一直点,那么请求就会一直发布出去。这里正确的思路应该是第一次点击就发送,然后上一个请求回来后,才能再发。

        核心思想:间隔执行,保证在特定时间内至少执行一次,无论事件触发频率如何。某个操作希望上一次的完成后再进行下一次,或者希望隔一段时间触发一次。节流就是减少流量,将频繁触发的事件减少,并每隔一段时间执行。即,控制事件触发的频率

        执行步骤:事件触发之后,执行操作,然后设置一个定时器,在设定时间内相同的事件触发无效,过了定时器的时间后,操作才可以再次触发。

节流方式一:时间戳方式

function throttle(func, interval) {let lastTime = 0;return function (...args) {const context = this;const now = Date.now();if (now - lastTime >= interval) {func.apply(context, args);lastTime = now;}};
}// 使用示例
function handleScroll() {console.log('滚动事件处理');
}const scrollArea = document.getElementById('scrollArea');
// 对 handleScroll 函数进行节流处理,时间间隔为 500 毫秒
scrollArea.addEventListener('scroll', throttle(handleScroll, 500));
  • throttle 函数接收两个参数,func 是需要进行节流处理的函数,interval 是时间间隔。
  • 利用 lastTime 变量记录上一次函数执行的时间。
  • 每次事件触发时,获取当前时间 now,通过计算 now - lastTime 判断是否超过了设定的时间间隔。如果超过了,就执行函数并更新 lastTime

节流方式二:定时器实现方式

function throttle(func, interval) {let timer = null;return function (...args) {const context = this;if (!timer) {func.apply(context, args);timer = setTimeout(() => {timer = null;}, interval);}};
}// 使用示例
function handleClick() {console.log('按钮点击处理');
}const button = document.getElementById('button');
// 对 handleClick 函数进行节流处理,时间间隔为 1000 毫秒
button.addEventListener('click', throttle(handleClick, 1000));

节流方式三:时间戳和定时器结合

function throttle(func, interval) {let lastTime = 0;let timer = null;return function (...args) {const context = this;const now = Date.now();const remaining = interval - (now - lastTime);clearTimeout(timer);if (remaining <= 0) {func.apply(context, args);lastTime = now;} else {timer = setTimeout(() => {func.apply(context, args);lastTime = Date.now();}, remaining);}};
}

        这种结合方式综合了时间戳和定时器的优点,既能保证在开始时立即执行函数,又能在后续按照固定时间间隔执行。

综合示例:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Debounce vs Throttle 可视化演示</title><style>body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }.demo-box { border: 2px solid #ddd; padding: 20px; margin: 20px 0; border-radius: 8px; }.stats { background: #f5f5f5; padding: 10px; margin: 10px 0; }.interactive-area { height: 150px; border: 2px dashed #999; margin: 10px 0; display: flex; align-items: center; justify-content: center; }</style>
</head>
<body><h1>防抖(Debounce) vs 节流(Throttle)</h1><!-- 输入框防抖演示 --><div class="demo-box"><h3>1. 输入框搜索 - 防抖演示</h3><input type="text" id="searchInput" placeholder="输入内容观察防抖效果"><div class="stats">输入事件触发: <span id="inputCount">0</span> 次,实际处理: <span id="inputProcessed">0</span> 次</div></div><!-- 按钮点击防抖/节流演示 --><div class="demo-box"><h3>2. 按钮点击 - 防抖 vs 节流</h3><button id="debounceBtn">防抖按钮(1秒内只响应首次)</button><button id="throttleBtn">节流按钮(1秒内只响应一次)</button><div class="stats">防抖点击: <span id="debounceClick">0</span> 次,节流点击: <span id="throttleClick">0</span> 次</div></div><!-- 滚动节流演示 --><div class="demo-box"><h3>3. 滚动事件 - 节流演示</h3><div class="interactive-area" id="scrollArea">滚动此区域</div><div class="stats">滚动事件触发: <span id="scrollCount">0</span> 次,实际处理: <span id="scrollProcessed">0</span> 次</div></div><!-- 鼠标移动防抖演示 --><div class="demo-box"><h3>4. 鼠标移动 - 防抖 vs 节流</h3><div class="interactive-area" id="mouseArea">在此移动鼠标</div><div class="stats">防抖处理: <span id="debounceMouse">0</span> 次,节流处理: <span id="throttleMouse">0</span> 次</div></div><script>// ================= 工具函数 =================// 防抖函数(支持立即执行)function debounce(func, delay = 300, immediate = false) {let timer;return function(...args) {const context = this;const isFirstCall = !timer;clearTimeout(timer);if (immediate && isFirstCall) func.apply(context, args);timer = setTimeout(() => {timer = null;if (!immediate) func.apply(context, args);}, delay);};}// 节流函数(结合时间戳和定时器)function throttle(func, interval = 300) {let lastTime = 0, timer;return function(...args) {const context = this;const now = Date.now();const remaining = interval - (now - lastTime);clearTimeout(timer);if (remaining <= 0) {func.apply(context, args);lastTime = now;} else if (!timer) {timer = setTimeout(() => {func.apply(context, args);lastTime = Date.now();timer = null;}, remaining);}};}// ================= 示例逻辑 =================// 1. 输入框防抖const searchInput = document.getElementById('searchInput');let inputCount = 0, inputProcessed = 0;searchInput.addEventListener('input', () => {document.getElementById('inputCount').textContent = ++inputCount;});const processSearch = debounce(() => {document.getElementById('inputProcessed').textContent = ++inputProcessed;}, 500);searchInput.addEventListener('input', processSearch);// 2. 按钮点击const debounceBtn = document.getElementById('debounceBtn');const throttleBtn = document.getElementById('throttleBtn');let debounceClick = 0, throttleClick = 0;debounceBtn.addEventListener('click', debounce(() => {document.getElementById('debounceClick').textContent = ++debounceClick;}, 1000, true));throttleBtn.addEventListener('click', throttle(() => {document.getElementById('throttleClick').textContent = ++throttleClick;}, 1000));// 3. 滚动节流const scrollArea = document.getElementById('scrollArea');let scrollCount = 0, scrollProcessed = 0;scrollArea.addEventListener('scroll', () => {document.getElementById('scrollCount').textContent = ++scrollCount;});scrollArea.addEventListener('scroll', throttle(() => {document.getElementById('scrollProcessed').textContent = ++scrollProcessed;}, 500));// 4. 鼠标移动对比const mouseArea = document.getElementById('mouseArea');let debounceMouse = 0, throttleMouse = 0;// 防抖处理(延迟200ms)mouseArea.addEventListener('mousemove', debounce(() => {document.getElementById('debounceMouse').textContent = ++debounceMouse;}, 200));// 节流处理(每200ms执行一次)mouseArea.addEventListener('mousemove', throttle(() => {document.getElementById('throttleMouse').textContent = ++throttleMouse;}, 200));</script>
</body>
</html>

下面对上述代码中的四个例子分别进行分析:

1.输入框搜索-防抖演示
// 获取输入框元素
const searchInput = document.getElementById('searchInput');
// 记录输入事件触发的次数
let inputCount = 0;
// 记录实际处理的次数
let inputProcessed = 0;// 监听输入框的 input 事件,每次触发时更新输入事件触发的次数
searchInput.addEventListener('input', () => {document.getElementById('inputCount').textContent = ++inputCount;
});// 创建一个经过防抖处理的函数
const processSearch = debounce(() => {// 每次执行时更新实际处理的次数document.getElementById('inputProcessed').textContent = ++inputProcessed;
}, 500);
// 监听输入框的 input 事件,使用经过防抖处理的函数
searchInput.addEventListener('input', processSearch);

  • 功能:演示输入框输入时的防抖效果。当用户在输入框中输入内容时,input 事件会频繁触发,inputCount 会实时记录触发次数。而 processSearch 是经过防抖处理的函数,它会在用户停止输入 500 毫秒后才执行,inputProcessed 记录实际处理的次数。
  • 原理:使用 debounce 函数对输入事件处理函数进行包装,确保在用户停止输入一段时间后才执行实际处理逻辑,避免不必要的频繁处理。
2. 按钮点击防抖/节流演示
// 获取防抖按钮元素
const debounceBtn = document.getElementById('debounceBtn');
// 获取节流按钮元素
const throttleBtn = document.getElementById('throttleBtn');
// 记录防抖按钮点击的次数
let debounceClick = 0;
// 记录节流按钮点击的次数
let throttleClick = 0;// 监听防抖按钮的 click 事件,使用经过防抖处理的函数
debounceBtn.addEventListener('click', debounce(() => {// 每次执行时更新防抖按钮点击的次数document.getElementById('debounceClick').textContent = ++debounceClick;
}, 1000, true));// 监听节流按钮的 click 事件,使用经过节流处理的函数
throttleBtn.addEventListener('click', throttle(() => {// 每次执行时更新节流按钮点击的次数document.getElementById('throttleClick').textContent = ++throttleClick;
}, 1000));

  • 功能:演示按钮点击时的防抖和节流效果。debounceBtn 是防抖按钮,在 1 秒内多次点击,只有首次点击会立即响应;throttleBtn 是节流按钮,在 1 秒内无论点击多少次,只会响应一次。
  • 原理
    • 防抖:使用 debounce 函数对按钮点击事件处理函数进行包装,设置 immediate 为 true 表示首次点击立即执行,后续点击会在 1 秒内无新点击时才执行。
    • 节流:使用 throttle 函数对按钮点击事件处理函数进行包装,确保在 1 秒内最多执行一次处理函数。

3. 滚动节流演示 

// 获取滚动区域元素
const scrollArea = document.getElementById('scrollArea');
// 记录滚动事件触发的次数
let scrollCount = 0;
// 记录实际处理的次数
let scrollProcessed = 0;// 监听滚动区域的 scroll 事件,每次触发时更新滚动事件触发的次数
scrollArea.addEventListener('scroll', () => {document.getElementById('scrollCount').textContent = ++scrollCount;
});// 监听滚动区域的 scroll 事件,使用经过节流处理的函数
scrollArea.addEventListener('scroll', throttle(() => {// 每次执行时更新实际处理的次数document.getElementById('scrollProcessed').textContent = ++scrollProcessed;
}, 500));

  • 功能:演示滚动事件的节流效果。当用户滚动 scrollArea 区域时,scroll 事件会频繁触发,scrollCount 会实时记录触发次数。而经过节流处理的函数会确保每 500 毫秒最多执行一次,scrollProcessed 记录实际处理的次数。
  • 原理:使用 throttle 函数对滚动事件处理函数进行包装,通过时间戳和定时器结合的方式,控制处理函数的执行频率,避免频繁处理滚动事件。

4. 鼠标移动防抖演示

// 获取鼠标移动区域元素
const mouseArea = document.getElementById('mouseArea');
// 记录鼠标移动防抖处理的次数
let debounceMouse = 0;
// 记录鼠标移动节流处理的次数
let throttleMouse = 0;// 监听鼠标移动区域的 mousemove 事件,使用经过防抖处理的函数
mouseArea.addEventListener('mousemove', debounce(() => {// 每次执行时更新鼠标移动防抖处理的次数document.getElementById('debounceMouse').textContent = ++debounceMouse;
}, 200));// 监听鼠标移动区域的 mousemove 事件,使用经过节流处理的函数
mouseArea.addEventListener('mousemove', throttle(() => {// 每次执行时更新鼠标移动节流处理的次数document.getElementById('throttleMouse').textContent = ++throttleMouse;
}, 200));

  • 功能:演示鼠标移动时的防抖和节流效果。当用户在 mouseArea 区域移动鼠标时,mousemove 事件会频繁触发。经过防抖处理的函数会在用户停止移动鼠标 200 毫秒后执行,而经过节流处理的函数会确保每 200 毫秒最多执行一次。
  • 原理
    • 防抖:使用 debounce 函数对鼠标移动事件处理函数进行包装,确保在用户停止移动鼠标一段时间后才执行实际处理逻辑。
    • 节流:使用 throttle 函数对鼠标移动事件处理函数进行包装,控制处理函数的执行频率,避免频繁处理鼠标移动事件。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com