简单实现节流函数踩的小坑

平时debounce(防抖)用得多,throttle用得少,记下写 throttle 时遇到的低级错误。
节流,一定时间内多次操作,在最早操作的若干延迟后执行。
场景参考:周期上报,有的数据不急着报,只要定时上报即可,开发者可能在多个地方调用周期上报,只需把数据存起来一起报即可。

防抖,一定时间内多次操作,在最后一次操作的若干延迟后执行。
场景参考:搜索框输入后立即进行搜索,当用户输入不改变 500毫秒后才向服务器发请求。

一开始写的节流函数是这样的

// 节流
function throttle(func, delay) {
  let throttleTimer = null
  return function() {
    let _this = this
    let _args = arguments
    if(!throttleTimer) {
      throttleTimer = setTimeout(()=>{
        func.apply(_this, _args)
        throttleTimer = null
      }, delay)
    }
    return throttleTimer
  }
}

这里假设滚动屏幕后要上报一下

const t = throttle((a)=>{
  console.log(a)
}, 1000)
let timer = null
window.onscroll = ()=>{
  const m = Math.random()
  console.log('随机值:', m)
  timer = t(m)
}

可以发现实际用了第一个参数在这里插入图片描述
好像不符合预期? 怎么不是用最后一个的参数?
直觉上不对,加日志看看

// 节流
function throttle(func, delay) {
  let throttleTimer = null
  return function() {
    let _this = this
    let _args = arguments
    console.debug('预期_args更新了', _args)
    if(!throttleTimer) {
      throttleTimer = setTimeout(()=>{
        func.apply(_this, _args)
        throttleTimer = null
      }, delay)
    }
    return throttleTimer
  }
}

在这里插入图片描述
可以看到_args确实有更新的,但 setTimeout 里打出来的仍是第一次的_args的值。
再看看,原来是_args重新定义了。
如果把_args挪到前面,行成闭包,就符合预期了。

// 节流
function throttle(func, delay) {
  let throttleTimer = null
  let _args // 把 args 定义放这,形成闭包
  return function() {
    let _this = this
    _args = arguments
    if(!throttleTimer) {
      throttleTimer = setTimeout(()=>{
        func.apply(_this, _args)
        throttleTimer = null
      }, delay)
    }
    return throttleTimer
  }
}

在这里插入图片描述
这里是变量作用域导致的,一开始_args的作用域在 throttle 返回的函数里,当调用了一次函数 t,setTimeout 里存着_args的值。
在这里插入图片描述
下次调用函数 t,_args重新定义,就是新的内存地址了,再去改变他的值并不改变之前 setTimeout 传入参数的值。
而把_args作用域提升到 throttle 里,就形成了闭包,我们代码对 t 有引用,_args跟throttleTimer就一直在。
在这里插入图片描述在这里插入图片描述
setTimeout 的_args就一直用的同一份,之后多次调用函数 t,更新_args的值就生效了。

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

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

相关文章

week04day03(爬虫 beautifulsoup4、)

一. 使用bs4解析网页 下载bs4 - pip install beautifulsoup4 使用的时候 import bs4专门用于解析网页的第三方库 在使用bs4的时候往往会依赖另一个库lxml pip install lxml 网页代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><…

什么是测试?测试测什么?

笔者是软件测试方向的硕士研究生。作为应届生拿下了20余个软件测试、测试开发的offer。 《校招生如何准备测试》系列会将我的测试理论体系与大家分享、探讨和学习。本期主要串联一下什么是测试、软件测试测什么&#xff08;测试类型&#xff09;。 Q&#xff1a;什么是软件测…

(十三)【Jmeter】线程(Threads(Users))之tearDown 线程组

简述 操作路径如下: 作用:在正式测试结束后执行清理操作,如关闭连接、释放资源等。配置:设置清理操作的采样器、执行顺序等参数。使用场景:确保在测试结束后应用程序恢复到正常状态,避免资源泄漏或对其他测试的影响。优点:提供清理操作,确保测试环境的整洁和可重复性…

铭瑄科技——为星闪技术发展与应用带来新推力

随着智能化生活逐渐普及&#xff0c;无线通信不仅是不仅是信息时代的重要基础设施&#xff0c;而且是推动社会向智能化发展的核心力量之一&#xff0c;其中短距无线通信更是推动未来智能化发展的关键。 为积极推动未来硬件智能化、产业智能化发展&#xff0c;铭瑄正式宣布成为星…

Codeforces Round 928 (Div. 4)

目录 A. Vlad and the Best of Five B. Vlad and Shapes C. Vlad and a Sum of Sum of Digits D. Vlad and Division E. Vlad and an Odd Ordering F. Vlad and Avoiding X G. Vlad and Trouble at MIT A. Vlad and the Best of Five 我们可以使用string中的count函数来…

《VitePress 简易速速上手小册》第8章 安全性与部署(2024 最新版)

文章目录 8.1 安全最佳实践8.1.1 基础知识点解析8.1.2 重点案例&#xff1a;个人博客8.1.3 拓展案例 1&#xff1a;在线商店8.1.4 拓展案例 2&#xff1a;企业网站 8.2 部署到 GitHub Pages 和其他平台8.2.1 基础知识点解析8.2.2 重点案例&#xff1a;个人博客部署到 GitHub Pa…

时序预测demo 代码快速实现 MLP效果比LSTM 好,简单模拟数据

【PyTorch修炼】用pytorch写一个经常用来测试时序模型的简单常规套路&#xff08;LSTM多步迭代预测&#xff09; 层数的理解&#xff1a; LSTM&#xff08;长短期记忆&#xff09;的层数指的是在神经网络中堆叠的LSTM单元的数量。层数决定了网络能够学习的复杂性和深度。每一层…

SQL- left join 与group by联合使用实例

表&#xff1a;Visits ---------------------- | Column Name | Type | ---------------------- | visit_id | int | | customer_id | int | ---------------------- visit_id 是该表中具有唯一值的列。 该表包含有关光临过购物中心的顾客的信息。表&#xff1a…

Docker容器与虚拟化技术:kylin 部署 docker容器应用

目录 一、实验 1.环境 2. kylin 部署 docker及版本升级 3.kylin 部署docker镜像加速 4.kylin 部署 nginx容器应用 5.kylin使用docker容器部署mysql实现数据持久化 6.kylin使用docker容器部署nginx实现配置文件持久化到本地 7.kylin 使⽤ docker 部署容器可视化平台porta…

【青龙】快速搭建青龙面板,部署属于你自己的应用!

青龙面板是一个支持 Python3、JavaScript、Shell、Typescript 的定时任务管理平台。 废话不多说&#xff0c;直接开始。 这里使用一台 雨云 的云服务器作为演示。雨云注册地址&#xff1a;https://www.rainyun.com/ 优惠码&#xff1a;lz932 使用优惠码注册后绑定微信可获得8折…

Spring框架@Autowired注解进行字段时,使用父类类型接收子类变量,可以注入成功吗?(@Autowired源码跟踪)

一、 前言 平常我们在使用spring框架开发项目过程中&#xff0c;会使用Autowired注解进行属性依赖注入&#xff0c;一般我们都是声明接口类型来接收接口实现变量&#xff0c;那么使用父类类型接收子类变量&#xff0c;可以注入成功吗&#xff1f;答案是肯定可以的&#xff01;…

从零学习Linux操作系统第二十七部分 shell脚本中的变量

一、什么是变量 变量的定义 定义本身 变量就是内存一片区域的地址 变量存在的意义 命令无法操作一直变化的目标 用一串固定的字符来表示不固定的目标可以解决此问题 二、变量的类型及命名规范 环境级别 export A1 在环境关闭后变量失效 退出后 关闭 用户级别&#xff…

Java项目:24 基于SpringBoot+freemarker实现的人事管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 基于SpringBootfreemarker实现的人事管理系统分为七大模块&#xff1a;绩效考核&#xff0c;招聘管理&#xff0c;档案管理&#xff0c;工资管…

Marin说PCB之如何使用mentor--xpedition-Valor软件做gerber_compare

首先打开mentro_xpedition,自带的Valor软件。 2&#xff0c;在File栏中选择import---odb。 3&#xff0c;导入生成的DOB文件。 4&#xff0c;在这个界面下再重新导入一份之前的参考板的ODB文件进来。 5&#xff0c;接着点击STEPS---board,这样单板的数据就被调进来了。 6&#…

《剑指Offer》笔记题解思路技巧优化_Part_6

《剑指Offer》笔记&题解&思路&技巧&优化_Part_6 &#x1f60d;&#x1f60d;&#x1f60d; 相知&#x1f64c;&#x1f64c;&#x1f64c; 相识&#x1f622;&#x1f622;&#x1f622; 开始刷题&#x1f7e1;1.LCR 168. 丑数—— 丑数&#x1f7e2;2. LCR 16…

2022蓝帽杯取证初赛

检材&#xff1a;https://pan.baidu.com/s/1ibOdxyCWeC5x0DQKjwcz7w?pwdvg6g 目录 手机取证1、627604C2-C586-48C1-AA16-FF33C3022159.PNG图片的分辨率是&#xff1f;&#xff08;答案参考格式&#xff1a;19201080&#xff09;2、姜总的快递单号是多少&#xff1f;&#xff0…

C++学习Day09之异常变量的生命周期

目录 一、程序及输出1.1 throw MyException()------catch (MyException e)1.2 throw MyException()------catch (MyException &e)1.3 throw &MyException()------catch (MyException *e)1.4 throw new MyException()------catch (MyException *e) 二、分析与总结 一、程…

QT3作业

1 2. 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数&#xff0c;将登录按钮使用t5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#…

【C++初阶】系统实现日期类

目录 一.运算符重载实现各个接口 1.小于 (d1)<> 2.等于 (d1d2) 3.小于等于&#xff08;d1<d2&#xff09; 4.大于&#xff08;d1>d2&#xff09; 5.大于等于&#xff08;d1>d2&#xff09; 6.不等于&#xff08;d1!d2&#xff09; 7.日期天数 (1) 算…

顺序表详解(如何实现顺序表)

文章目录 前言 在进入顺序表前&#xff0c;我们先要明白&#xff0c;数据结构的基本概念。 一、数据结构的基本概念 1.1什么是数据结构 数据结构是由“数据”和“结构”两词组合而来。所谓数据就是&#xff1f;常见的数值1、2、3、4.....、姓名、性别、年龄&#xff0c;等。…