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 函数对鼠标移动事件处理函数进行包装,控制处理函数的执行频率,避免频繁处理鼠标移动事件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/41854.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C/C++算法】从浅到深学习--- 简单模拟算法(图文兼备 + 源码详解)

绪论&#xff1a;冲击蓝桥杯一起加油&#xff01;&#xff01; 每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 本篇是一些简单的模拟算法&#xff0c;其中模拟的本质就是就是根据题目意思进行代码的…

​​解锁 JavaScript DOM:节点操作的核心方法与最佳实践

引言 在当今动态化的 Web 世界中&#xff0c;用户早已不满足于静态的网页展示&#xff0c;而是期待流畅的交互体验——点击按钮弹出菜单、滚动页面加载数据、实时搜索过滤内容……这些功能的背后&#xff0c;都离不开 ​JavaScript DOM&#xff08;文档对象模型&#xff09;操…

Android 12系统源码_系统启动(二)Zygote进程

前言 Zygote&#xff08;意为“受精卵”&#xff09;是 Android 系统中的一个核心进程&#xff0c;负责 孵化&#xff08;fork&#xff09;应用进程&#xff0c;以优化应用启动速度和内存占用。它是 Android 系统启动后第一个由 init 进程启动的 Java 进程&#xff0c;后续所有…

精华贴分享|从不同的交易理论来理解头肩形态,殊途同归

本文来源于量化小论坛策略分享会板块精华帖&#xff0c;作者为孙小迪&#xff0c;发布于2025年2月17日。 以下为精华帖正文&#xff1a; 01 前言 学习了一段时间交易后&#xff0c;我发现在几百年的历史中&#xff0c;不同门派的交易理论对同一种市场特征的称呼不一样&#x…

C++智能指针万字详细讲解(包含智能指针的模拟实现)

在笔试&#xff0c;面试中智能指针经常出现&#xff0c;如果你对智能指针的作用&#xff0c;原理&#xff0c;用法不了解&#xff0c;那么可以看看这篇博客讲解&#xff0c;此外本博客还简单模拟实现了各种指针&#xff0c;在本篇的最后还应对面试题对智能指针的知识点进行了拓…

学习threejs,使用多面体(IcosahedronGeometry、TetrahedronGeometry、OctahedronGeometry等)

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.PolyhedronGeometry …

DeepSeek详解:探索下一代语言模型

文章目录 前言一、什么是DeepSeek二、DeepSeek核心技术2.1 Transformer架构2.1.1 自注意力机制 (Self-Attention Mechanism)(a) 核心思想(b) 计算过程(c) 代码实现 2.1.2 多头注意力 (Multi-Head Attention)(a) 核心思想(b) 工作原理(c) 数学描述(d) 代码实现 2.1.3 位置编码 (…

【目标检测】【深度学习】【Pytorch版本】YOLOV1模型算法详解

【目标检测】【深度学习】【Pytorch版本】YOLOV1模型算法详解 文章目录 【目标检测】【深度学习】【Pytorch版本】YOLOV1模型算法详解前言YOLOV1的模型结构YOLOV1模型的基本执行流程YOLOV1模型的网络参数YOLOV1模型的训练方式 YOLOV1的核心思想前向传播阶段网格单元(grid cell)…

网络运维学习笔记(DeepSeek优化版) 022 HCIP-Datacom路由概念、BFD协议详解与OSPF第一课

文章目录 路由概念、BFD协议详解与OSPF第一课一、路由协议优先级与选路原则1.1 路由协议优先级对照表1.2 路由选路核心原则 二、BFD&#xff08;Bidirectional Forwarding Detection&#xff0c;双向转发检测&#xff09;的配置与应用2.1 双向心跳探测&#xff08;双端配置&…

单应性矩阵(homography)

利用单应性矩阵计算内外参矩阵 利用单应性矩阵解决问题 问题描述&#xff1a;

Scavenge算法的优缺点问题

Scavenge 的缺点是只能使用堆内存中的一半&#xff0c;这是由划分空间和复制机制所决定的。但 Scavenge 由于只复制存活的对象&#xff0c;并且对于生命周期短的场景&#xff0c;存活对象只占少部分&#xff0c;所以它在时间效率上有优异的表现。 由于 Scavenge 是典型的牺牲空…

丝杆支撑座间隙调整不当会带来哪些影响?

丝杆支撑座是一种用于支撑滚珠丝杆的零件&#xff0c;通常用于机床、数控机床、自动化生产线等高精度机械设备中。支撑座间隙调整不当会对机械设备的运行产生多方面的影响&#xff0c;接下来一起了解一下&#xff1a; 1、降低加工精度&#xff1a;在机械加工设备中&#xff0c;…

Unity:EasyRoad3D插件学习 二期

前言&#xff1a; 书接上回。 一、场景视图状态&#xff1a; 创建好道路以后&#xff0c;切换到第一个选项&#xff0c;场景视图状态&#xff0c;查看道路信息&#xff0c;Main Settings修改道路名称、类型&#xff0c;宽度&#xff0c;是否闭环。 RoadWidth改为15&#xff…

内网渗透-DLL和C语言加载木马

免杀进阶技术 1、DLL的定义与使用 DLL:Dynamic Link library,动态链接库&#xff0c;是一个无法自己运行&#xff0c;需要额外的命令或程序来对其接口进行调用&#xff08;类方法、函数&#xff09;。 (1)在DevCpp中创建一个DLL项目 (2)在dllmain.c中定义源代码函数接口 #i…

一洽让常见问题的快速咨询,触手可及

在客户服务场景中&#xff0c;重复性常见问题的处理效率直接影响用户体验与客服成本。针对重复性常见问题&#xff0c;如何以直观的方式呈现给用户&#xff0c;使其能够快速、精准地提出咨询&#xff0c;已成为提升客户满意度的关键因素。 一、传统客服模式的效率枷锁 用户咨…

WEB攻防-Java安全SPEL表达式SSTI模版注入XXEJDBCMyBatis注入

目录 靶场搭建 JavaSec ​编辑​编辑 Hello-Java-Sec(可看到代码对比) SQL注入-JDBC(Java语言连接数据库) 1、采用Statement方法拼接SQL语句 2.PrepareStatement会对SQL语句进行预编译&#xff0c;但如果直接采取拼接的方式构造SQL&#xff0c;此时进行预编译也无用。 3、…

树莓集团南京园区启航:数字经济新地标!

深耕数字产业&#xff0c;构筑生态闭环 树莓集团在数字产业领域拥有超过十年的深厚积累&#xff0c;专注于构建“数字产业”的融合生态链。其核心优势在于有效整合政府、产业、企业及高校资源&#xff0c;形成一个协同创新、价值共生的产业生态闭环系统。 赋能转型&#xff0c…

Redis之bimap/hyperloglog/GEO

bimap/hyperloglog/GEO的真实需求 这些需求的痛点&#xff1a;亿级数据的收集清洗统计展现。一句话&#xff1a;存的进取得快多维度 真正有价值的是统计。 统计的类型 亿级系统中常见的四种统计 聚合统计 统计多个集合元素的聚合结果&#xff0c;就是交差并等集合统计。 排…

nara wpe去混响学习笔记

文章目录 1.WPE方法去混响的基本流程1.1.基本流程 2.离线迭代方法3.在线求法3.1.回顾卡尔曼方法3.2.在线去混响递推滤波器G方法 nara wpe git地址 博客中demo代码下载 参考论文 NARA - WPE: A Python Package for Weighted Prediction Error Dereverberation in Numpy and Ten…

JavaScript函数、箭头函数、匿名函数

1.示例代码(包括用法和注意事项) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>JS-函数</title…