【JavaScript】面试手撕节流

news2024/9/19 10:49:52

引入

上篇我们讲了防抖,这篇我们就谈谈防抖的好兄弟 – 节流。这里在老生常谈般的提一下他们两者之间的区别,顺带给读者巩固下。

PS: 开源节流中节流与这个技术上的节流,个人认为本质上是一样的。

  • 开源节流的节流指的是节省公司的金钱开支。
  • 前端技术上的节流指的是稀释函数的调用频率,节省CPU的开支。

区别

  • 节流: N 秒内只运行一次,若在N秒内重复触发,只有第一次生效
  • 防抖: N 秒后在执行该事件,若在N秒内被重复触发,则重新计时

不过我认为还是防抖那篇文章有个读者的评论更显生动 🐶, 在此对该读者表示感谢🙏。

  • 节流: 可以看做攻击间隔,点的再快没打出来也不会同时攻击两次。
  • 防抖: 可以理解为回城,每点一下就要重新跑.

节流例子

这里我举两个常见的🌰,大家有什么更好的🌰可以在评论里回复
这个王者荣耀的攻击例子也算是节流,不过这个我就不举了。🐶

生活例子

这里跟大家举一个生活例子,更显生动。

我们知道一般女神回复舔🐶的概率都是比较低的,假设女神每天回复舔🐶一次。也就是说如果今天女生已经回复过了,那么无论舔🐶发再多的信息对方也是不会回的。今天的次数已经消耗完毕了,也只能等明天才能刷新。

短信验证

我们知道短信验证是在生活中很常见,其实短信验证便用到了节流的技术。
因为发短信其实是要钱的,为了避免一个用户重复点击导致发出多条短信就要使用节流。比如获取一次验证码的有效时间为60秒,则60秒内这个发送短信的方法不能再次触发。

手撕代码

xdm,接下来开始手撕代码了。这里有两种实现方式,分别是时间戳实现和定时器实现。

时间戳实现

原理

每次事件触发都会检查距离上次执行的时间间隔,如果超过指定的等待时间delay,则执行函数。并且更新上一次执行时间为为当前的时间戳。

代码
function throttleByTimestamp(fn, wait) {
  let lastTime = 0; // 用于保存上一次执行的时间戳

  return function () {
    const currentTime = new Date().getTime();
    // 判断当前时间与上次执行时间差是否大于等待时间
    if (currentTime - lastTime > wait) {
      // 如果满足条件,则执行原函数,并传递参数
      fn.apply(this, arguments);
      // 更新上一次执行的时间戳为当前时间
      lastTime = currentTime;
    }
  };
}

// 使用
const throttledFn = throttleByTimestamp(function () {
  console.log("节流函数被执行");
}, 500); // 每隔500毫秒执行一次

// 等待时间
const waitTime = async (time) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, time);
  });
};

const main = async() => {
    throttledFn();
    // 换成 < 500ms的则只会执行一次
    await waitTime(600);
    throttledFn();
}

main()

/**
 * 输出:
 * 节流函数被执行
 * 节流函数被执行
 */

定时器实现

原理

我们在事件触发时设置一个定时器。

  • 首次事件触发时,我们设置一个定时器,在等待一段时间后执行函数。
  • 当定时器触发前,如果有新的事件触发,我们会检查是否存在定时器,如果存在则跳过。
  • 当定时器触发时,会清除当前定时器,确保下一次事件能重新触发。
代码

注: 测试例子跟上面的一样,此处不在贴啦。

function throttleByTimer(fn, delay) {
  let timer;
  return function () {
    const context = this;
    const args = arguments;
    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(context, args);
        clearTimeout(timer);
        timer = null;
      }, delay);
    }
  };
}

时间戳+定时器实现

我们回顾这两个实现方式,大家有没有发现这两个实现方式的区别?

  • 时间戳: 因为是拿当前时间减上一次触发的时间,所以一旦满足该条件,事件会立即执行。
  • 定时器: 由于fn.apply的函数写在了setTimeout里,所以触发了,也得等delay后才能执行,于是就有了这种事件停止触发后依然会再一次执行的效果。

如果我们要实现这样的一个需求,完成一个事件触发时立即执行,触发完毕还能执行一次的节流函数该如何做呢?

原理

此处借鉴掘金网友《6个瑞士卷》的分析,个人觉得逻辑写的很好。于是摘录了下来。

  • 需要在每个delay时间中一定会执行一次函数,因此在节流函数内部使用开始时间、当前时间与delay来计算remaining
  • remaining <= 0时表示该执行函数了,如果还没到时间的话就设定在remaining时间后再触发。
  • 当然在remaining这段时间中如果又一次发生事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。
代码
function throttle(fn, delay) {
  let timer;
  let lastTime = 0;

  return function () {
    let currentTime = Date.now();
    // 计算距离上次执行fn到现在过去了多少时间,与delay做比较
    let remaining = delay - (currentTime - lastTime);
    const context = this;
    const args = arguments;

    // 如果在remaining这段时间在发生,会取消当前的计时器
    clearTimeout(timer);
    // 当remaining <= 0时表示该执行函数了
    if (remaining <= 0) {
      fn.apply(context, args);
      lastTime = Date.now();
    } else {
      // 如果还没到时间的话就设定在remaining时间后再触发
      timer = setTimeout(fn, remaining);
    }
  };
}

借鉴文章

  1. JS简单实现防抖和节流

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

#stm学习总结 (二十八)硬件随机数实验

28.1 随机数发生器简介 STM32F407 自带了硬件随机数发生器&#xff08;RNG&#xff09;&#xff0c;RNG 处理器是一个以连续模拟噪声为基础的随机数发生器&#xff0c;在主机读数时提供一个 32 位的随机数。 28.1.1 RNG 框图 STM32F407 的随机数发生器&#xff08;RNG&#x…

Python实现双向链表:从基础到应用

一、引言 双向链表是一种比单向链表更复杂的数据结构&#xff0c;每个节点除了包含数据和指向下一个节点的指针外&#xff0c;还包含一个指向前一个节点的指针。这种结构使得我们可以从链表的任何节点开始&#xff0c;向前或向后遍历链表。 目录 一、引言 二、节点定义 三、…

谷歌最强开源大模型亮相!Gemini技术下放,笔记本就能跑,可商用

明敏 发自 凹非寺 量子位 | 公众号 QbitAI 谷歌大模型&#xff0c;开源了&#xff01; 一夜之间&#xff0c;Gemma系列正式上线&#xff0c;全面对外开放。 它采用Gemini同款技术架构&#xff0c;主打开源和轻量级&#xff0c;免费可用、模型权重开源、允许商用&#xff0c;…

C++ STL:set/multiset、map/multimap源码剖析

C STL中set和map底层数据结构为红黑树rb_tree。具体可以参考这篇文章。 ​​​​​​C STL &#xff1a;红黑树rb_tree源码剖析-CSDN博客 set插入时插的就是key&#xff0c; map插入时插的是value(键值对)&#xff0c; 排序时底层的红黑树会根据key_compare(也就是模版…

[回归指标]R2、PCC(Pearson’s r )

R2相关系数 R2相关系数很熟悉了&#xff0c;就不具体解释了。 皮尔逊相关系数&#xff08;PCC&#xff09; 皮尔逊相关系数是研究变量之间线性相关程度的量&#xff0c;R方和PCC是不同的指标。R方衡量x和y的接近程度&#xff0c;PCC衡量的是x和y的变化趋势是否相同。R方是不…

可用于智能客服的完全开源免费商用的知识库项目

介绍 FastWiki项目是一个高性能、基于最新技术栈的知识库系统&#xff0c;专为大规模信息检索和智能搜索设计。利用微软Semantic Kernel进行深度学习和自然语言处理&#xff0c;结合.NET 8和MasaBlazor前端框架&#xff0c;后台采用.NET 8MasaFrameworkSemanticKernel&#xff…

深入理解Java泛型及其在实际编程中的应用

第1章&#xff1a;泛型的起源与重要性 大家好&#xff0c;我是小黑&#xff0c;在Java里&#xff0c;泛型&#xff08;Generics&#xff09;是一种不可或缺的特性&#xff0c;它允许咱们在编码时使用类型&#xff08;Type&#xff09;作为参数。这听起来可能有点绕&#xff0c…

LeetCode 2581.统计可能的树根数目:换根DP(树形DP)

【LetMeFly】2581.统计可能的树根数目&#xff1a;换根DP(树形DP) 力扣题目链接&#xff1a;https://leetcode.cn/problems/count-number-of-possible-root-nodes/ Alice 有一棵 n 个节点的树&#xff0c;节点编号为 0 到 n - 1 。树用一个长度为 n - 1 的二维整数数组 edges…

文件基础和文件fd

文章目录 预备知识C语言的文件接口系统调用文件fd 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 人工智能学习网站&#xff0c; 通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站。 预备知识 我们平时说文件就是说文件里…

园区停车管理系统的设计与实现

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一 、设计说明 1.1 选题…

第十四篇【传奇开心果系列】Python的文本和语音相互转换库技术点案例示例:深度解读Azure Cognitive Services个性化推荐系统

传奇开心果博文系列 系列博文目录Python的文本和语音相互转换库技术点案例示例系列 博文目录前言一、个性化推荐系统介绍和关键功能以及优势解说二、雏形示例代码三、个性化推荐示例代码四、实时推荐示例代码五、多种推荐算法示例代码六、易于集成示例代码七、数据安全和隐私保…

minio多版本

minio的多版本是怎么实现的 1、界面上传3次1M文件&#xff0c;可以显示3个版本的 2、在文件名1M目录下会有3个uuid为名的目录 3、其中的xl.meta文件可以使用xl-meta工具解析&#xff0c;这里会记录详细的版本信息 {"Versions": [{"Header": {"Flag…

快速下载Huggingface的大语言模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Huggingface是什么&#xff1f;二、基于官方huggingface-cli下载&#xff08;基础&#xff0c;断线风险&#xff09;1.安装hf下载环境2.配置环境变量3.注册…

Container killed on request. Exit code is 143

Bug信息 WARN YarnAllocator: Container marked as failed: container_e33_1480922439133_0845_02_000002 on host: hdp4. Exit status: 143. Diagnostics: Container killed on request. Exit code is 143 Container exited with a non-zero exit code 143 Killed by externa…

css 面试 px,rem,em 区别

一、px是决定单位&#xff0c;一旦设置了就无法因为适应页面大小而改变。 二、em和rem 是相对长度单位&#xff0c; 相对于px更具有灵活性&#xff0c;更适用于响应式布局。 三、em是相对于其父元素来设置字体大小的&#xff0c;一般都是以<body>的“font-size”为基准…

Java核心-异常处理

上一次学完了Java的核心类与API&#xff0c;这次来学习异常处理。我们都知道&#xff0c;Java语言具有健壮性和安全性&#xff0c;而异常处理机制就是其重要保证。如下 一、类型 错误(Error)和异常(Exception)。这里只讨论 Exception 类型的异常处理。 1、错误(Error) Err…

浏览器卡顿解决办法 —— DNS设置

1.Windows - 设置 2.网络和Internet 3.以太网 - 更改适配器选项 4.点击你现在用的网络 (WLAN或以太网)&#xff0c;右键属性 5.双击IPv4协议&#xff0c;DNS地址首选114.114.114.114 南京信风网络科技有限公司&#xff0c;成立于2000年&#xff0c;是一家位于中国南京的高…

LeetCode215.数组中的第K个最大元素

题目 给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 输入: [3,2,1,5,6,4], …

基于springboot + vue实现的前后端分离-在线旅游网站系统(项目 + 论文)

项目介绍 本旅游网站系统采用的数据库是MYSQL &#xff0c;使用 JSP 技术开发&#xff0c;在设计过程中&#xff0c;充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。 技术选型 后端: SpringBoot Mybatis 数据库 : MyS…

大模型日报|今日必读的6篇大模型论文

大家好&#xff0c;今日必读的大模型论文来啦&#xff01; 1.中科院、国科大新研究&#xff1a;进行自我感知、更接近人类的AI “机器能思考吗&#xff1f;”这个问题和评估机器是否能达到人类智能水平的图灵测试&#xff0c;是人工智能&#xff08;AI&#xff09;的核心问题…