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

news2024/11/16 8:29:22

平时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的值就生效了。

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

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

相关文章

OpenWRT部署web站点并结合内网穿透实现无公网ip远程访问

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器,目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器,并且和…

医疗行业的数字化转型:开发智慧医疗源码与互联网医院APP教学

今天,笔者将与大家共同了解医疗行业的数字化转型过程,重点关注开发智能医疗源码以及互联网医院APP的实践指南,希望能够为医疗机构的数字化建设提供有益的参考和指导。 一、数字化转型背景与意义 数字化转型则可以通过智能化技术,…

基于Android的大学生足球赛事管理系统的设计与实现

足球是世界范围内广受欢迎的一种体育运动,国内有中超、中甲及大学生联赛等各级别的赛事,中超和中甲基本上都有专业的球队在运营,而大学生联赛属于校园级别的赛事,其重视程度较为有限,使得其信息化水平不高,…

昇腾ACL应用开发之模型转换ATC

一.前提条件 在前面的章节中我们已经安装了包含模型转换的套件包CANN-TOOLKIT,默认的安装路径会在/usr/local/Ascend里面,我们将该套件所需要的东西加入到环境变量中以便我们调用: 将source /usr/local/Ascend/ascend-toolkit/set_env.sh加入…

yml配置文件中常见的配置及含义

1.数据库连接的相关配置 项目名称:datasource:driver-class-name: com.mysql.cj.jdbc.Driverhost: localhostport: 3306database: 数据库名username: 用户名password: 密码 springboot配置文件,用于配置数据库源连接信息 数据库驱动类型为com.mysql.cj.jdbc.Driver,这是数据…

35岁测试经理自述:为何我做测试十年,内心仍无比恐慌?

记得在求职的时候,面试官经常问我:“为什么要选择软件测试工作?” 而我也会经常说一堆自己有的没的优势去应付。 工作这么久了,也不再浮躁,静下心来回忆当初选择软件测试工作的历程,也是对自己职业生涯的一次回顾。 …

vulnhub靶场之Deathnote

一.环境搭建 1.靶场描述 Level - easy Description : dont waste too much time thinking outside the box . It is a Straight forward box . This works better with VirtualBox rather than VMware 2.靶场下载 https://www.vulnhub.com/entry/deathnote-1,739/ 3.启动环…

图——最小生成树实现(Kruskal算法,prime算法)

目录 预备知识: 最小生成树概念: Kruskal算法: 代码实现如下: 测试: Prime算法 : 代码实现如下: 测试: 结语: 预备知识: 连通图:在无向图…

手写线程池(JUC复习自用)

手写线程池(复习自用) 介绍代码 介绍 参考黑马满老师的JUC课程,给代码加上了相应的注释 如图所示,线程池核心线程数为1,任务队列的容量为1,假设要执行的线程数为4个,首先取一个放入线程池运行&a…

SpringBoot-2.7.6如何自定义自动配置和starter

1.Starter SpringBoot中的一大优势就是starter,SpringBoot也提供了很多开箱即用的starter依赖,使得我们开发变更加方便和简单,遵循约定大于配置的理念。 启动器是一组方便的依赖描述符,您可以将其包含在应用程序中。您可以获得所需的所有Spring和相关技术的一站式商店,而…

uni-app搭建h5项目

一、 打开官方网站 https://uniapp.dcloud.net.cn/quickstart-cli.html 二、找到使用vue-cli命令行,按照文档上的步骤进行搭建 全局安装 vue-cli npm install -g vue/cli搭建项目 可以根据命令行搭建,搭建vue2.0对应的是webpack, 也可以搭…

A2L文件添加结构体数组测量量,并进行测试

首先看到如下的待测的结构体数组变量是一个7x50的一个Uint32,相当于二维数组。 在A2L文件的Map File中搜索当前变量并新建为Map测量量 然后在Overview中选择当前结构体,选择属性Properties 选择数据类型为Ulong,就是uint32类型 配置map解析的…

【Python常用包】typing

目录 typing准备工作typing 实践Tuple、List、DictTuple - 用于定义元组类型的类型注解Dict - 用于定义字典类型的类型注解List - 用于定义列表类型的类型注解 UnionOptional 小结 typing 在 Python 中,typing 模块提供了一些辅助工具来帮助开发者编写类型注解&…

JAVA工程师面试专题-并发编程篇

目录 一、线程 1、并发与并行的区别 2、同步和异步的区别 3、Java中创建线程有哪些方式? 4、Thread和Runnable的区别 5、Java中的Runnable、Callable、Future、FutureTask的区别和联系? 6、说一下你对 CompletableFuture 的理解 7、volatile关键字有什么用&…

css2的三大特性

css的三大特性 一.层叠性概念 二.继承性行高的继承 三. 优先级概念a标签默认蓝色优先级注意事项 一.层叠性 概念 二.继承性 行高的继承 可用倍数表示三. 优先级 概念 a标签默认蓝色 优先级注意事项 例子

基于ExtendSim的半导体制造工厂仿真

这是一个离散事件模型,使用ExtendeSim “高级资源管理(ARM)”功能来组织和分配资源。 此模型使用离散事件仿真和高级资源管理(ARM)功能。ARM是一个集成系统,用于组织资源、区分资源并在整个模型中分配资源。…

java效率为什么比c/c++慢,蓝桥杯上java只得50分,c++通过?

java效率为什么比c/c慢,蓝桥杯上java只得50分,c通过? 在开始前我有一些资料,是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大…

nginx 具体介绍

一,nginx 介绍 (一)nginx 与apache 1, Apache event 模型 相对于 prefork 模式 可以同时处理更多的请求 相对于 worker 模式 解决了keepalive场景下,长期被占用的线程的资源浪费问题 因为有监听线程&#…

[游戏开发][虚幻5]新建项目注意事项

鼠标右键点击Client.uproject文件,可以看到三个比较关键的选项, 启动游戏,生成sln解决方案,切换引擎版本 断点调试 C代码重要步骤 如果你想断点调试C代码,则必须使用使用代码编译启动引擎,你需要做几个操作…

容器_Docker ( 05 )

容器_Docker ( 04 ) K8S管理 集群管理 集群管理命令 kubectl是用于控制Kubernetes集群的命令行工具 语法格式 : kubectl [command] [Type] [Name] [flags] command : 子命令 , 如create , get , describe , delete 查询集群信息管理命令 子命令说明help用于查看命令及子命…