当前位置: 首页 > news >正文

JavaScript中的防抖与节流:提升性能的关键技巧

文章目录

  • JavaScript 中的防抖与节流:提升性能的关键技巧
    • 一、防抖(Debounce)
      • 1.1 概念
      • 1.2 应用场景
      • 1.3 代码实现
    • 二、节流(Throttle)
      • 2.1 概念
      • 2.2 应用场景
      • 2.3 代码实现
        • 2.3.1 时间戳方式
        • 2.3.2 定时器方式
    • 三、防抖与节流的区别
    • 四、总结

JavaScript 中的防抖与节流:提升性能的关键技巧

在 JavaScript 开发的过程中,我们经常会与各种高频触发事件打交道,例如窗口大小调整、滚动条滚动以及输入框输入等。倘若对这些事件处理得不够妥当,极有可能引发性能方面的问题,甚至对用户体验产生负面影响。而防抖(Debounce)和节流(Throttle)技术,正是解决此类问题的得力工具。

一、防抖(Debounce)

1.1 概念

防抖的核心思路是:当某个事件被触发时,会设定一个延迟时间。在这个延迟时间之内,如果该事件再次被触发,那么之前设置的延迟定时器就会被清除,然后重新开始计时。只有当延迟时间结束,并且在这期间没有再次触发该事件时,我们真正期望执行的函数才会被执行。这就好比你在使用自动门,当你快速进出多次时,自动门不会每次都立即关闭,而是在你最后一次通过后,等待一段时间才关闭,这个等待的过程就类似于防抖中的延迟时间 。

1.2 应用场景

搜索框输入:在用户进行搜索操作时,每输入一个字符就可能触发一次搜索请求。如果不进行防抖处理,会频繁地向服务器发送请求,这不仅会增加服务器的负载压力,还可能导致网络资源的浪费。通过防抖技术,我们可以设定在用户停止输入 300 毫秒后,再发起搜索请求。这样一来,只有当用户输入完成并暂停一段时间后,才会触发搜索操作,大大减少了不必要的请求次数。

窗口大小调整:当用户调整浏览器窗口大小时,会持续触发 resize 事件。如果在这个事件处理函数中执行复杂的布局调整操作,如重新计算元素的位置和大小、重新渲染页面等,频繁的触发会导致大量的计算任务,严重影响页面的性能。使用防抖技术,能够确保在用户停止调整窗口一段时间后,才执行布局调整相关的操作,有效避免了频繁计算带来的性能损耗。

图片懒加载:在图片较多的页面中,当图片即将进入视口时会触发相关事件来加载图片。利用防抖可以避免在图片快速接近视口边界时多次触发加载函数,只有当图片稳定在视口内一段时间后才加载,减少不必要的加载请求。例如在一个商品展示页面,有大量商品图片,使用防抖可以优化图片加载,提升页面加载速度。

WebSocket 连接管理:当网络状态不稳定时,可能会频繁触发连接状态变化事件。通过防抖,在网络状态频繁变化时不会立即尝试重新连接 WebSocket,而是在网络状态稳定一段时间后再进行连接操作,避免频繁的无效连接尝试,节省网络资源和服务器压力。

1.3 代码实现

// 定义防抖函数function debounce(func, delay) {// 声明一个变量timer,用于存储定时器的标识let timer;// 返回一个新的函数,这个函数就是我们实际使用的防抖函数return function() {// 获取当前函数执行时的上下文对象,通常是调用该函数的对象,这里用this表示const context = this;// 获取当前函数执行时传入的参数,用arguments对象来存储const args = arguments;// 如果timer存在,说明之前已经设置了定时器,并且还未到达延迟时间if (timer) {// 清除之前设置的定时器,重新开始计时clearTimeout(timer);}// 设置一个新的定时器,在延迟时间delay毫秒后执行传入的函数func// 使用apply方法来调用func,确保func执行时的上下文对象为context,传入的参数为argstimer = setTimeout(() => {func.apply(context, args);}, delay);};
}// 定义一个处理搜索操作的函数
function handleSearch() {console.log('执行搜索操作');
}
// 使用debounce函数对handleSearch函数进行防抖处理,延迟时间为300毫秒
const debouncedSearch = debounce(handleSearch, 300);
// 为id为searchInput的输入框添加input事件监听器,当输入框内容发生变化时,调用debouncedSearch函数
document.getElementById('searchInput').addEventListener('input', debouncedSearch);

二、节流(Throttle)

2.1 概念

节流指的是在一定的时间间隔内,无论事件被触发多少次,都只会执行一次函数。可以将其理解为对事件的触发频率进行 “节流”,使得事件处理函数按照我们预先设定的时间间隔来执行。比如水龙头的水流控制,无论你怎么快速地开关水龙头,在一定时间内,流出的水量是有限的,这就类似于节流对事件触发频率的限制。

2.2 应用场景

滚动事件:当用户滚动页面时,会频繁地触发 scroll 事件。如果在这个事件处理函数中执行一些如加载更多数据、判断元素是否进入视口等操作,不加限制地频繁执行这些操作,会消耗大量的系统资源,导致页面卡顿。通过节流技术,我们可以设定每 1000 毫秒执行一次加载更多数据的操作,这样既能满足用户的浏览需求,又能保证页面的流畅性。

鼠标点击:在某些特定的场景下,我们可能需要限制用户点击按钮的频率。例如,在提交表单的场景中,如果用户快速多次点击提交按钮,可能会导致重复提交数据,给服务器带来不必要的压力,甚至可能引发数据一致性问题。使用节流技术,我们可以设定每 500 毫秒只能点击一次提交按钮,有效避免了重复操作带来的问题。

游戏开发:在游戏中,玩家的一些操作(如射击、跳跃等)可能会被玩家快速重复触发。通过节流,我们可以限制玩家操作的频率,确保游戏逻辑的稳定性。例如在一个射击游戏中,限制玩家每 0.5 秒只能射击一次,避免玩家通过快速点击射击按钮获得不公平的优势。

文件上传进度监控:在上传大文件时,会频繁触发上传进度事件。使用节流可以控制进度更新的频率,避免因频繁更新进度条而占用过多资源,影响文件上传的效率和页面的响应速度。

2.3 代码实现

2.3.1 时间戳方式
// 定义节流函数,采用时间戳方式
function throttle(func, interval) {// 记录上一次函数执行的时间,初始值为0let lastTime = 0;// 返回一个新的函数,这个函数就是我们实际使用的节流函数return function() {// 获取当前时间的时间戳const now = Date.now();// 获取当前函数执行时的上下文对象,通常是调用该函数的对象,这里用this表示const context = this;// 获取当前函数执行时传入的参数,用arguments对象来存储const args = arguments;// 判断当前时间与上一次函数执行时间的差值是否大于等于设定的时间间隔intervalif (now - lastTime >= interval) {// 如果满足条件,执行传入的函数func// 使用apply方法来调用func,确保func执行时的上下文对象为context,传入的参数为argsfunc.apply(context, args);// 更新上一次函数执行的时间为当前时间lastTime = now;}};
}
// 定义一个加载更多数据的函数
function loadMoreData() {console.log('加载更多数据');
}
// 使用throttle函数对loadMoreData函数进行节流处理,时间间隔为1000毫秒
const throttledLoadMore = throttle(loadMoreData, 1000);
// 为window对象添加scroll事件监听器,当页面滚动时,调用throttledLoadMore函数
window.addEventListener('scroll', throttledLoadMore);
2.3.2 定时器方式
// 定义节流函数,采用定时器方式
function throttle(func, interval) {// 声明一个变量timer,用于存储定时器的标识let timer;// 返回一个新的函数,这个函数就是我们实际使用的节流函数return function() {// 获取当前函数执行时的上下文对象,通常是调用该函数的对象,这里用this表示const context = this;// 获取当前函数执行时传入的参数,用arguments对象来存储const args = arguments;// 如果timer不存在,说明当前处于可以执行函数的时间间隔内if (!timer) {// 执行传入的函数func// 使用apply方法来调用func,确保func执行时的上下文对象为context,传入的参数为argsfunc.apply(context, args);// 设置一个定时器,在时间间隔interval毫秒后将timer重置为null// 这样在下一次函数调用时,timer为null,就可以再次执行函数timer = setTimeout(() => {timer = null;}, interval);}};
}
// 定义一个处理按钮点击的函数
function handleClick() {console.log('按钮点击处理');
}
// 使用throttle函数对handleClick函数进行节流处理,时间间隔为500毫秒
const throttledClick = throttle(handleClick, 500);
// 为id为clickButton的按钮添加click事件监听器,当按钮被点击时,调用throttledClick函数
document.getElementById('clickButton').addEventListener('click', throttledClick);

三、防抖与节流的区别

执行时机:防抖是在事件停止触发后的延迟时间结束后才执行函数;而节流是按照固定的时间间隔执行函数,与事件是否停止触发没有关系。

应用场景:防抖更适用于那些需要在用户操作结束后执行一次的场景,比如搜索框输入、文本编辑器的保存操作等;节流则更适用于需要限制事件触发频率的场景,像滚动事件、频繁点击事件以及一些需要控制数据更新频率的场景。

四、总结

防抖和节流是 JavaScript 开发中极为实用的性能优化技巧。合理运用这两种技术,能够显著减少不必要的计算和请求,从而有效提升页面的性能以及用户体验。在实际的开发过程中,我们需要依据具体的业务场景和需求,精准地选择合适的技术来优化代码,以实现更加高效、流畅的应用程序。

如果你还想了解它们在特定框架(如 Vue、React)中的应用,或者想进一步优化代码示例,都可以随时告诉我,我会继续完善这篇博客。


http://www.mrgr.cn/news/90057.html

相关文章:

  • DeepSeek 的详细介绍与使用,和本地部署的介绍
  • 单片机之基本元器件的工作原理
  • vscode和pycharm的区别
  • Python(pymysql包)操作MySQL【增删改查】
  • 题海拾贝:【高精度】减法
  • 【数据结构】(6) LinkedList 链表
  • 保姆级教程Docker部署Zookeeper官方镜像
  • 第3章 城市隧道工程与城市轨道交通工程 3.2 地下水控制
  • 【AIGC】DeepSeek本地部署方法详解:基于Ollama与LM-Studio
  • deepseek+kimi自动生成ppt
  • 策略模式(Strategy)
  • react 路由配置:从入门到精通
  • 解锁 DeepSeek 模型高效部署密码:蓝耘平台深度剖析与实战应用
  • 区块链技术未来发展趋势(人工智能和物联网领域)
  • 【计算机网络】TCP/IP 网络模型有哪几层?
  • 寒假集训思维训练1题解
  • [Meet DeepSeek] 如何顺畅使用DeepSeek?告别【服务器繁忙,请稍后再试。】
  • deepseek v3网络结构源码分析笔记
  • 5. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--微服务基础工具与技术--Nacos
  • Win10 部署llama Factory 推荐教程和遇到的问题
  • 大数据项目4:基于spark的智慧交通项目设计与实现
  • 【通俗易懂说模型】反向传播(附多元分类与Softmax函数)
  • 【虚幻引擎UE】UE4.23到UE5.5的核心功能变化
  • LLMs之DeepSeek r1:TinyZero(复现 DeepSeek R1 Zero 的核心功能)的简介、安装和使用方法、案例应用之详细攻略
  • [概率论] 随机变量
  • CPLD实现SPI通信