js语法---理解防抖原理和实现方法

什么是防抖(节流)

        在实际的网页交互中,如果一个事件高频率的触发,这会占用很多内存资源,但是实际上又并不需要监听触发如此多次这个事件(比如说,在抢有限数量的优惠券时,用户往往会提前在短时间内高频率的点击按钮,但是我只需要接受多次点击中的一次点击,判断有没有抢到即可),这个时候就需要防抖来减少监听的次数,

        防抖就是在多次触发事件时,减少对冗余事件的监听(主要包括,只保留一次监听一定事件内只触发一次监听),

防抖使用场景 :在原有需求能实现的前提下减少多余操作

原理和示例

事件案例

以下是一个点击事件的展示,我们希望判断这个按钮有没有被点击(只要又打印结果即可)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>防抖</title>
</head>
<body>
  <button id="bt">点击</button>
  <script src="index.js"></script>
</body>
</html>
const bt = document.getElementById('bt');
const click = () => {
  console.log('点击了按钮');
}

bt.addEventListener('click', click);

可以看到短时间内用户可能会多次点击按钮,但是我们只需要一次打印就可以判断出用户是否点击了按钮,所以这里有16次的事件冗余。 

设置防抖

思路:在用户多次点击按钮时,我们选择保留最后一次事件触发,即在点击到事件触发这段时间,如果用户再点击,则将上一次点击的操作取消,而等待执行新点击的操作,以此类推;

const bt = document.getElementById('bt');
let timer;// 声明一个全局的定时器变量
const click = () => {
  clearTimeout(timer);// 清除之前的定时器
  timer = setTimeout(() => { // 延时触发操作
    console.log('点击了按钮');
  }, 500);
}

bt.addEventListener('click', click);

         这里的代码要注意这个定时器变量,它要在click函数体外,因为它要在click触发时保存上一次的定时器,并对其实现清楚,如果出现在click函数体内,则会因为每次都产生新的定时器且无法捕获到上一次的定时器,而导致所有打印延迟生效,没有被清楚

此时在点击按钮时,不会立刻打印结果,而多次点击时,由于旧的定时器不断被清楚,打印操作都不会被触发,直到停下点击之后的0.5s才会出现打印结果

封装一个防抖函数

了解了防抖的基本实现,我们封装一个防抖函数以便于对函数的时间间隔防抖功能实现,

防抖函数,它应该接受两个参数,一个是要执行的函数一个是执行函数的间隔,并且返回一个有防抖效果的函数

/**
 * @param fun 要执行的操作
 * @param time 执行的间隔
 * @return 返回有防抖效果的原操作
 * */
const FD = (fun, time) => {
  let timer;// 闭包储存定时器变量
  return function () {
    if (!timer) {
      timer = setInterval(() => {
        fun();
        clearInterval(timer);// 清除定时器
        timer = null;// 重置定时器变量
      }, time);
    }
  }
}

因为要有一个变量来保存定时器的状态,所以这采用闭包的形式保存这个timer,这样每次执行这个FD的返回函数时,timer的值都会保留下来而不是被覆盖,

关于闭包的解释可以参考:js闭包------简单理解闭包含义_js 闭包累加-CSDN博客

使用实例

监听一个页面滚动的事件,打印出滚动的高度,用防抖减少打印的次数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>防抖</title>
</head>
<body style="height: 200vh;">
  <button id="bt">点击</button>
  <script src="index.js"></script>
</body>
</html>
window.onscroll = () => {
  console.log('滚动的距离', window.scrollY);
}

这里即使是滚动一小段距离也会多次触发打印

滚动了300的距离就触发多次打印,

/**
 * @param fun 要执行的操作
 * @param time 执行的间隔
 * @return 返回有防抖效果的原操作
 * */
const FD = (fun, time) => {
  let timer;// 闭包储存定时器变量
  return function () {
    if (!timer) {
      timer = setInterval(() => {
        fun();
        clearInterval(timer);// 清除定时器
        timer = null;// 重置定时器变量
      }, time);
    }
  }
}

window.onscroll = FD(() => {
  console.log('滚动的距离', window.scrollY);
},500);

有了防抖之后,0.5秒只触发一次打印,大大减少了事件触发

完整代码展示

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>防抖</title>
</head>
<body style="height: 200vh;">
  <button id="bt">点击</button>
  <script src="index.js"></script>
</body>
</html>

index.js: 

// 1.声明一个变量,储存定时器,
// 2.在点击事件中,先清除之前的定时器,再设置新的定时器,
// 3.设置定时器延时操作,相当于等待操作执行结束,才会执行下一次操作(防抖)

const bt = document.getElementById('bt');
let timer;// 声明一个全局的定时器变量
const click = () => {
  clearTimeout(timer);// 清除之前的定时器
  timer = setTimeout(() => { // 延时触发操作
    console.log('点击了按钮');
  }, 500);
}

bt.addEventListener('click', click);

// 多次点击,只执行最后一次操作(节流)


// 节流

/**
 * @param fun 要执行的操作
 * @param time 执行的间隔
 * @return 返回有防抖效果的原操作
 * */
const FD = (fun, time) => {
  let timer;// 闭包储存定时器变量
  return function () {
    if (!timer) {
      timer = setInterval(() => {
        fun();
        clearInterval(timer);// 清除定时器
        timer = null;// 重置定时器变量
      }, time);
    }
  }
}


// window.onscroll = () => {
//   console.log('滚动的距离', window.scrollY);
// }

window.onscroll = FD(() => {
  console.log('滚动的距离', window.scrollY);
},500);

// 滚动时,每隔500ms打印一次滚动的距离

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

golang windows打包为linux可执行文件

使用go的交叉编译功能 set GOOSlinux set GOARCHamd64然后再执行go build 可能会报异常, 所以贴出我的go env配置仅供参考 go env环境配置 D:\GoWork\src\go-tzv>go env set GO111MODULEauto set GOARCHamd64 set GOBIN …

架构师篇-1、总体架构设计

业务架构哲学本质 定位&#xff1a;赋予业务架构设计能力&#xff0c;具备业务架构设计思维模型&#xff0c;掌握业务架构哲学本质&#xff0c;形成以不变应万变的业务架构设计能力。 架构师所需要的能力&#xff1a; 带领业务成功通过框架思维赋能业务架构师知识体系构建掌…

华北水利水电大学-C程序设计作业

目录 基础题 1-1 分析 代码实现 1-2 分析 代码实现 1-3 分析 代码实现 1-4 ​编辑 分析 代码实现 1-5 分析 代码实现 1-6 分析 代码实现 基础题 1-1 从键盘输入10个学生的有关数据&#xff0c;然后把它们转存到磁盘文件上去。其中学生信息包括学号、姓名…

学会python——制作一款天气查询工具(python实例七)

目录 1、认识Python 2、环境与工具 2.1 python环境 2.2 Visual Studio Code编译 3、天气查询工具 3.1 代码构思 3.2 代码示例 3.3 运行结果 4、总结 1、认识Python Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的…

pip安装总是失败,如何配置pip安装源,让环境重获新生?

前情提要 公司新项目组报道后&#xff0c;因为用的是公司内网&#xff0c;安装完python 和pycharm 后&#xff0c;发现pip 下载安装包总是报错 具体解决 1.确认python 环境已经安装 2.在cmd中执行如下命令配置参数 pip config set global.index-url https://这里填写自己公…

Linux 软件包管理器 yum

文章目录 yum是什么&#xff1f;Linux(centos)的生态yum的相关操作yum本地配置安装包lrzsz yum是什么&#xff1f; yum可以形象的比喻成一个下载安装管理的一个客户端&#xff0c;比如小米应用商店、华为应用商城 Linux中的安装包是有依赖关系的(比如下载游戏的时候有各种文件…

神经网络模型---ResNet

一、ResNet 1.导入包 import tensorflow as tf from tensorflow.keras import layers, models, datasets, optimizersoptimizers是用于更新模型参数以最小化损失函数的算法 2.加载数据集、归一化、转为独热编码的内容一致 3.增加颜色通道 train_images train_images[...,…

滑动窗口练习1-长度最小的子数组

1.题目链接&#xff1a;209.长度最小的子数组 2.题目描述&#xff1a; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条…

【机器学习】第9章 降维算法——PCA降维

一、概念 1.PCA &#xff08;1&#xff09;主成分分析&#xff08;Principal ComponentAnalysis&#xff0c;PCA&#xff09;一种经典的线性降维分析算法。 &#xff08;2&#xff09;原理&#xff0c;这里以二维转一维为例&#xff0c;原来的平面变成了一条直线 这是三维变二…

git 基本命令

列出分支基本命令&#xff1a; git branch 如果我们要手动创建一个分支 。执行 git branch (branchname) 即可&#xff1a; git branch testing 切换到testing分支&#xff1a; git checkout testing 我们也可以使用 git checkout -b (branchname) 命令来创建新分支并立…

1504 - Java多线程面试题

少年&#xff0c;思无邪&#xff0c;最最动人。 1.Java中有哪几种创建线程的方式 1.1 继承Thread类 代码示例 class HelloWorld01 extends Thread{Overridepublic void run() {System.out.println("这是继承 Thread 类方式实现多线程!");} }public class CreateTh…

Redis 高可用 sentinel

简介 Sentinel提供了一种高可用方案来抵抗节点故障&#xff0c;当故障发生时Redis集群可以自动进行主从切换&#xff0c;程序可以不用重启。 Redis Sentinel集群可以看成是一个Zookeeper集群&#xff0c;他是Redis集群高可用的心脏&#xff0c;一般由3-5个节点组成&#xff0…

从“产品的RFM分析”看如何探索“职业方向”

我们在做产品分析时&#xff0c;经常会用到一种方法“产品的RFM分析”&#xff0c;它是一种客户细分和价值评估的常用方法&#xff0c;广泛应用于电子商务、零售和其他众多行业&#xff0c;它可以帮助企业和产品团队更好地理解用户行为&#xff0c;优化营销策略&#xff0c;提升…

python发邮件给多人的注意事项?如何群发?

python发邮件给多人的效率如何&#xff1f;python发邮件的方法&#xff1f; 在利用Python编程语言实现邮件群发功能时&#xff0c;需要注意许多细节&#xff0c;以确保邮件能有效送达且用户体验良好。AokSend将详细探讨python发邮件给多人时需要注意的各个方面&#xff0c;以帮…

2024年历史、文学与人文艺术国际会议(ICHLH 2024)

2024年历史、文学与人文艺术国际会议&#xff08;ICHLH 2024&#xff09; 2024 International Conference on History, Literature, and Humanities 【重要信息】 大会地点&#xff1a;兰州 大会官网&#xff1a;http://www.ichlh.com 投稿邮箱&#xff1a;ichlhsub-conf.com 【…

【第10章】Vue之Element Plus常用组件

文章目录 前言一、表格1. 带斑马纹表格2. 展示 二、分页1.国际化(中文)2.分页代码3. 展示 三、表单1. 表单代码2. 展示 四、卡片1. 卡片代码2. 展示 总结 前言 通过上一章的快速入门&#xff0c;我们已经学习了按钮使用&#xff0c;接下来学习Element Plus的常用组件&#xff…

02-QWebEngineView的使用

Qt WebEngine_hitzsf的博客-CSDN博客 一、QWebEngineView QWebEngineView 类是一个实现Web浏览器的便捷类&#xff0c;提供了back() 、forward()、reload()、stop() 等方法&#xff0c;可轻松实现页面的前进、后退、重载等导航功能&#xff0c;要实现一个简单的只有网页加载网…

手机网站制作软件是哪些

手机网站制作软件是一种用于设计、开发和创建适用于移动设备的网站的软件工具。随着移动互联网时代的到来&#xff0c;越来越多的用户开始使用手机浏览网页和进行在线交流&#xff0c;因此&#xff0c;手机网站制作软件也逐渐成为了市场上的热门工具。 1. Adobe Dreamweaver&am…

前端某个页面乱码

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; springbootlayui&#xff0c;前后端一体 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 某个页面访问中文乱码&#xff1a; 就是这种。 不是数据库的中文&#xff0c;而是html页…

docker回顾--docker compose详细解释,安装,与常用命令

文章目录 Docker compose简介什么是Docker compose核心概念优势 安装常用命令总结 Docker compose简介 什么是Docker compose Docker Compose 是一个用于定义和运行多容器 Docker 应用的工具。它使得开发者可以使用一个单独的 YAML 文件来定义应用所需的所有服务、网络和卷&a…