彻底理清防抖和节流(前端性能优化)

server/2024/9/18 12:16:44/ 标签: 前端, javascript, 性能优化

目录

引言:

1.定义

防抖(Debounce)

节流(Throttle)

2.实现方式/原理

防抖:

节流:

 3.应用场景

防抖(Debounce):

节流(Throttle):

4.两者总结

相同点:

不同点:

补充:

上下文(Context)指的是什么?

什么时候使用上下文?


引言:

前端有很多性能优化的方式,面对用户与网页的频繁交互,如输入框打字、按钮点击、滚动事件等,我们如何确保应用的响应既迅速又高效?

大家应该都简单了解防抖和节流本质上就是优化这种高频率执行代码的手段那么他们之间有什么区别呢?应该如何正确根据具体的场景来选择使用呢?


1.定义

防抖(Debounce)

确保在指定的时间间隔内,无论连续触发了多少次事件,只有最后一次事件会在该间隔结束后执行。(触发事件后 n 秒后才执行函数,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。)

核心逻辑

  • 重置计时器:每次事件触发时,都会重置计时器。
  • 执行时机:只有在用户停止触发事件指定时间间隔后,才会执行最后一次事件。

举例:

想象一台自动售货机,里面都是不同价格的商品,当你投入相应的硬币,会自动选择对应商品。但是为了避免还没投完就出商品,售货机设计不是投完立即掉出商品,而是有一个短暂的延迟,在这个延迟期间,如果你再次投入硬币,售货机重新进入延迟,只有当延迟期过后,之前投入硬币才会被处理。这样可以避免因为误操作或快速连续操作导致的错误购买。

节流(Throttle)

确保在指定的时间间隔内,无论触发了多少次事件,只有第一次事件会被执行,后续事件在这个间隔内都不会执行。(连续触发事件但是在 n 秒中只执行第一次触发函数)

核心逻辑

  • 单次执行:在时间间隔内只执行一次事件处理函数。
  • 忽略后续触发:在时间间隔内,后续的事件触发将被忽略。

举例:

想象一个繁忙的十字路口,交通信号灯每60秒变换一次。不论有多少车辆通过,信号灯都不会更快地变换。这就像节流,无论事件触发的频率多高,每个周期内只执行一次。

2.实现方式/原理

防抖:
javascript">// 创建一个防抖函数,它返回一个新的函数,该新函数在指定的 wait 时间后执行 func
function debounce(func, wait) {// 保存定时器的引用let timeout;// 返回的函数是用户实际调用的函数,它包含了防抖逻辑return function(...args) {// 保存当前的 this 上下文const context = this;console.log(context);  // 清除之前的定时器,如果存在if (timeout) clearTimeout(timeout);  // 设置一个新的定时器// 当指定的 wait 时间过后,将执行 func 函数// 并将当前的 this 上下文和参数传入timeout = setTimeout(function() {  // 执行原始函数,绑定正确的 this 上下文和参数func.apply(context, args);  }, wait);  };
}
  • 当防抖函数被触发时,首先会检查是否已经存在一个timeout(即是否有一个定时器在运行)。
  • 如果存在,表示之前有触发过防抖函数但还未执行func,此时使用clearTimeout清除之前的定时器。
  • 然后,设置一个新的timeout,如果在wait指定的时间内再次触发防抖函数,之前的定时器会被清除并重新设置,这意味着func的执行会被不断推迟。
  • 只有当指定的时间间隔wait内没有再次触发防抖函数时,timeout才会到达,此时会执行原始函数func,并且使用apply方法将存储的contextargs传递给它。
节流:
javascript">function throttle(func, limit) {let inThrottle = false;return function(...args) {const context = this; // 保存当前的 this 上下文if (!inThrottle) {// 执行传入的函数func.apply(context, args);inThrottle = true; // 标记为正在节流// 使用闭包和 setTimeout 来在指定的延迟后重置 inThrottlesetTimeout(() => {inThrottle = false; // 重置节流状态}, limit);}};
}
  • func:需要被节流的函数。
  • limit:表示在指定的时间间隔后,func才能再次被执行的时间(以毫秒为单位)。
  • inThrottle:一个布尔值,用来标记func是否处于可执行状态。
  • context:保存当前的this上下文,确保在执行functhis指向正确。
  • args:使用扩展运算符...来收集所有参数,以便将它们传递给func
  • setTimeout:在指定的limit时间后执行,将inThrottle重置为false,这样func就可以在下一次调用时被执行了。

 3.应用场景

防抖(Debounce):

搜索框输入:当用户在搜索框中输入文本时,通常会有一些实时搜索建议。使用防抖可以确保只有在用户停止输入一段时间后才触发搜索请求,避免因为快速连续输入而导致的大量请求。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Debounced Search</title>
</head>
<body><input type="text" id="searchBox" placeholder="输入内容...">
<ul id="suggestionsList"></ul><script>// 防抖函数
function debounce(func, wait) {let timeout;return function(...args) {const context = this;clearTimeout(timeout);timeout = setTimeout(() => {func.apply(context, args);}, wait);};
}// 搜索建议函数(示例)
function showSuggestions(query) {const suggestionsList = document.getElementById('suggestionsList');// 这里使用 query 参数来模拟搜索建议逻辑suggestionsList.innerHTML = `<b>搜索: ${query}</b>`;console.log(`Searching for: ${query}`);
}// 获取搜索框元素和其 oninput 事件
const searchBox = document.getElementById('searchBox');// 使用防抖包装搜索建议函数,设置防抖时间为 1500 毫秒
const debouncedShowSuggestions = debounce(showSuggestions, 1500);// 绑定事件处理函数
searchBox.addEventListener('input', function(event) {// 使用 event.target.value 获取输入框的值const query = event.target.value;debouncedShowSuggestions(query);
});
</script>
</body>
</html>

当用户在搜索框中输入文本时,会触发 input 事件。我们绑定了一个防抖后的 showSuggestions 函数到这个事件上,这样当用户停止输入1500毫秒后,showSuggestions 函数才会执行,以此来模拟获取搜索建议的过程。

节流(Throttle):

滚动事件:在处理滚动事件时,如无限滚动加载更多内容,节流可以限制触发事件处理程序的频率,避免过度触发导致性能问题。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Throttled Infinite Scroll</title><style>#contentList {list-style: none;padding: 0;overflow-y: auto;height: 300px; /* 根据需要调整这个高度 */background: #f9f9f9;}#contentList li {padding: 10px;border-bottom: 1px solid #ddd;background-color: white;}</style>
</head>
<body><ul id="contentList"><!-- 初始内容列表项 --><li>Item 1</li><li>Item 2</li><!-- 更多内容根据滚动加载 -->
</ul><script>// 节流函数function throttle(func, limit) {let inProgress = false;return function() {if (!inProgress) {inProgress = true;setTimeout(() => {func.apply(this, arguments);inProgress = false;}, limit);}};}// 加载更多内容的函数function loadMoreContent() {const contentList = document.getElementById('contentList');// 检查是否滚动到距离底部 100 像素以内if (contentList.scrollTop + contentList.clientHeight + 100 >= contentList.scrollHeight) {console.log('加载更多内容...');// 这里模拟从服务器加载数据,实际上你应该发起 AJAX 请求setTimeout(() => {for (let i = 0; i < 5; i++) { // 每次加载 5 个新项const newItem = document.createElement('li');newItem.textContent = 'Item ' + (contentList.children.length + 1);contentList.appendChild(newItem);}}, 1000);}}// 获取滚动容器const contentListElement = document.getElementById('contentList');// 给滚动事件添加节流contentListElement.addEventListener('scroll', throttle(loadMoreContent, 1000));// 填充初始内容以确保可以滚动for (let i =2; i < 10; i++) {const listItem = document.createElement('li');listItem.textContent = 'Item ' + (i + 1);contentListElement.appendChild(listItem);}
</script>
</body>
</html>

4.两者总结

相同点:
  • 实现机制:两者都可以通过JavaScript的setTimeout函数实现,利用时间延迟来控制回调函数的执行。
  • 性能优化:它们的共同目的都是减少函数的执行频率,以此来提高程序的性能,避免不必要的计算资源消耗。
不同点:
  1. 执行时机

    • 防抖(Debounce):确保在指定的时间间隔结束后执行一次函数。如果在这段时间内多次触发事件,则只有最后一次事件会在延迟后执行函数。
    • 节流(Throttle):确保在指定的时间间隔内最多执行一次函数。无论在这段时间内触发了多少次事件,只有第一次事件会立即执行函数。
  2. 应用场景

    • 防抖:适用于搜索框输入、表单验证等场景,用户完成输入后,才执行相关操作。
    • 节流:适用于滚动事件、按钮点击等,需要在连续事件中合理控制执行频率的场景。
  3. 触发逻辑

    • 防抖:关注一段时间内的连续触发,但只对最后一次操作做出响应。
    • 节流:在一段时间内,无论触发多少次事件,只响应一次。
  4. 分辨技巧:

  • 如果您希望在一系列快速操作结束后只执行一次函数,那么使用防抖
  • 如果您希望在一系列快速操作中合理控制函数的执行频率,那么使用节流

补充:

上下文(Context)指的是什么?

上下文通常指的是this所指向的对象。在不同的函数调用方式中,this的指向可能不同:

  1. 全局上下文:在全局作用域中,this指向全局对象(在浏览器中是window)。
  2. 对象方法上下文:当一个函数作为对象的方法被调用时,this指向该对象。
  3. 构造函数上下文:在构造函数中,this指向新创建的实例。
  4. 事件处理上下文:在事件处理函数中,this通常指向触发事件的DOM元素。
什么时候使用上下文?
  1. 对象的方法:当您调用一个对象的方法,并且需要在该方法内部引用该对象的其他属性或方法时。

    javascript">const person = {name: 'John',greet() {console.log(`Hello, my name is ${this.name}.`);}
    };
    person.greet(); // 输出: Hello, my name is John.
  2. 事件处理器:在事件驱动的编程中,如DOM事件处理,您可能需要在事件处理函数中引用绑定事件的元素。

    javascript">const button = document.getElementById('myButton');
    button.addEventListener('click', function() {console.log(this); // 在这里,this 指向 button 元素
    });
  3. 构造函数:在使用构造函数创建实例时,this用于引用正在创建的新实例。

    javascript">function Person(name) {this.name = name;
    }
    const john = new Person('John');
    console.log(john.name); // 输出: John
  4. 模块或命名空间:在模块模式或命名空间中,this可以用来访问外部的全局上下文或另一个对象。

    javascript">const myModule = {name: 'My Module',logName: function() {console.log(this.name);}
    };


http://www.ppmy.cn/server/32537.html

相关文章

C语言如何理解返回指针的函数?

一、问题 有些函数的返回类型是指针类型&#xff0c;如何理解返回指针的函数&#xff1f; 二、解答 ⼀个函数可以带回⼀个整型值、字符值、实型值等&#xff0c;也可以带回指针型的数据&#xff0c;即地址。其概念与以前类似&#xff0c;只是带回的值的类型是指针类型⽽已。返…

华为LTC线索与回款中的线索培育工具:9格构想

在《LTC与铁三角∶从线索到回款-人民邮电.》一书中&#xff0c;说到线索的管理&#xff0c;书中的9格构想不错&#xff0c;收藏之&#xff1a; 九格构想这一工具的使用顺序依次是诊断原因、探究 影响、构想能力。 1. 诊断原因&#xff08; R1-R2-R3 &#xff09; 企业应先用…

【数据结构】第四讲:双向链表

目录 一、链表的分类 二、双向链表的结构及实现 1.带头双向链表的结构 2.创建节点 3.初始化 4.尾插 5.打印 6.头插 7.尾删 8.头删 9.在pos位置之后插入数据 10.删除pos节点 11.查找 12.销毁 个人主页&#xff1a;深情秋刀鱼-CSDN博客 数据结构专栏&#xff1a;数…

分布式事务—> seata

分布式事务之Seata 一、什么是分布式事务&#xff1f; 分布式事务是一种特殊类型的事务&#xff0c;它涉及多个分布式系统中的节点&#xff0c;包括事务的参与者、支持事务的服务器、资源服务器以及事务管理器。 在分布式事务中&#xff0c;一次大型操作通常由多个小操作组成…

扫雷实现详解【递归展开+首次必展开+标记雷+取消标记雷】

扫雷 一.扫雷设计思路二.扫雷代码逐步实现1.创建游戏菜单2.初始化棋盘3.打印棋盘4.随机布置雷5.统计周围雷的个数6.递归展开棋盘7.标记雷8.删除雷的标记9.保证第一次排雷的安全性棋盘必定展开10.排查雷11.判断输赢 三.扫雷总代码四.截图 一.扫雷设计思路 1.创建游戏菜单。  2.…

AD如何从外部导入外框或修改外框大小

一、从外部导入外框 1、从cad中导出dxf文件&#xff0c;从AD中导入导出的文件 2、可参考如下参数设置 3、导入确认后&#xff0c;选择外边框线&#xff08;选择一条边的线然后按Tab键可快速选择&#xff09; 4、到设计-板子形状中选择“按照选择对象定义” 5、板子外形已经出来…

【JavaEE】多线程安全问题

文章目录 1、什么是多线程安全问题2、出现线程不安全的原因2.1 线程在系统中是随机调度&#xff0c;抢占式执行的2.2 多个线程同时修改同一个变量2.3 线程针对变量的修改操作&#xff0c;不是“原子”的2.4 内存可见性问题2.5 指令重排序 3 、如何解决线程安全问题3.1 锁操作3.…

随便聊一下 显控科技 控制屏 通过 RS485 接口 上位机 通讯 说明

系统搭建&#xff1a; 1、自己研发的一个小系统&#xff08;采集信号&#xff0c;将采集的信号数字化&#xff09;通过COM口&#xff0c;连接显控屏 COM3 口采用 485 协议送到显控屏&#xff08;显控科技&#xff09;的显示屏展示出来&#xff09;。 2、显控屏 将 展示的数据…

第IV章-Ⅱ Vue3中的插槽使用

第IV章-Ⅱ Vue3中的插槽使用 基本插槽默认内容 具名插槽作用域插槽 在 Vue 3 中&#xff0c;插槽&#xff08;slots&#xff09;是一种强大的模式&#xff0c;用于将模板代码从父组件注入到子组件中&#xff0c;使得子组件的内容可以在使用时被自定义。Vue 3 中的插槽用法包括基…

Linux使用操作(二)

进程的管理_ps 程序运行在计算机操作系统中&#xff0c;由操作系统进行管理。为了管理正在运行的程序&#xff0c;每个程序在运行时都被注册到操作系统中&#xff0c;形成进程 每个进程都有一个独特的进程ID&#xff08;进程号&#xff09;&#xff0c;用来区别不同的进程。进…

网络安全:绕过 MSF 的一次渗透测试

这次渗透的主站是 一个 DiscuzDiscuz!3.4 的搭建 违法招 piao 网站&#xff0c; 配置有宝塔 WAF 用 Discuz!ML 3.X 的漏洞进行攻击&#xff0c;但是没有成功 现主站外链会有一个发卡网&#xff0c;引导人们来这充值&#xff0c;是 某某发卡网&#xff0c;而且域名指向也是主站…

区域文本提示的实时文本到图像生成;通过一致性自注意力机制的视频生成工具保持视频的一致性;专门为雪佛兰汽车设计的客服聊天机器人

✨ 1: StreamMultiDiffusion StreamMultiDiffusion是首个基于区域文本提示的实时文本到图像生成框架&#xff0c;实现了高速且互动的图像生成。 StreamMultiDiffusion 旨在结合加速推理技术和基于区域的文本提示控制&#xff0c;以克服之前解决方案中存在的速度慢和用户交互性…

Java项目:基于SSM框架实现的学院党员管理系统高校党员管理系统(ssm+B/S架构+源码+数据库+毕业论文+开题)

一、项目简介 本项目是一套基于SSM框架实现的学院党员管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能齐…

【QT】初始QT

目录 一.背景1.GUI开发的各种技术方案2.什么是框架3.QT支持的系统4.QT的版本5.QT的优点6.QT的应用常见 二.环境搭建1.认识QTSDK中的重要工具2.使用QT Creator创建项目3.项目解释(1)main.cpp(2)widget.h(3)widget.cpp(4)widget.ui(5)Empty.pro(6)临时文件 三.初始QT1.Hello Worl…

Linux CentOS 本地yum配置

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 我们这种老土程序员很难接受开…

生信分析最好的系统架构:个人观点

1. 宿主机系统 结论&#xff1a;CentOS7.9&#xff0c;宿主机的最佳主系统。推荐安装 Server with GUI。优点&#xff1a; 兼容各种外接硬件&#xff0c;包括磁盘、GPU等扩展。目前为止&#xff0c;CentOS硬件驱动等支持目前是最好的&#xff0c;这也是众多IT企业选择它的原因…

基于 AI 的数据库助手-Chat2DB

序言 现在已经开始步入 AI 时代&#xff0c;AI 产品也已经络绎不绝。今天&#xff0c;给大家介绍一款数据库的 AI 产品 —— Chat2DB。 一、什么是 Chat2DB Chat2DB 由阿里提供的一个数据库管理、数据开发、数据分析的工具&#xff0c;它是一个 AI 原生的数据库管理工具&…

PHP深入探索:面向对象编程与设计模式实战

摘要 PHP作为一种广泛应用于Web开发的服务器端脚本语言,其面向对象编程(OOP)特性与设计模式的应用,对于构建可维护、可扩展的高质量应用系统至关重要。本文旨在深入探讨PHP中的OOP概念,通过实战案例展现如何有效地结合设计模式,解决开发中的常见问题,提升代码的复用性和…

微图乐 多种装B截图一键制作工具(仅供娱乐交流)

软件介绍 采用exe进程交互通信。全新UI界面&#xff0c;让界面更加清爽简约。支持zfb、VX、TX、Yin行、Dai款、游戏等图片生成&#xff0c;一键超清原图复制到剪辑板&#xff0c;分享给好友。适用于提高商家信誉度&#xff0c;产品销售额度。装逼娱乐&#xff0c;用微图乐。图…

ssh远程访问windows系统下的jupyterlab

网上配置这一堆那一堆&#xff0c;特别乱&#xff0c;找了好久整理后发在这里 由于既想打游戏又想做深度学习&#xff0c;不舍得显卡性能白白消耗&#xff0c;这里尝试使用笔记本连接主机 OpenSSH 最初是为 Linux 系统开发的&#xff0c;现在也支持包括 Windows 和 macOS 在内…