debounce(防抖)和throttle(节流)小结

news2024/12/28 19:27:50

前端工程师们都听过看起来很高级的词,节流和防抖,其实节流就是throttle,防抖就是debounce,其实这个也属于前端性能优化的一部分。

  • 节流 像阀门一样控制水流,避免单位时间内流量过大
  • 防抖 防止抖动,比节流的流量控制效果更佳明显

在做远程搜索时,如果每输入1个字就调用1次接口,就会频繁查询数据库,假设我们的查询是"12345",不考虑用户输入错误的情况,至少会请求5次。

再思考一个问题,按钮的click重复触发(例如快速点击2次,3次,...n次)该如何在前端做一层拦截,避免发送重复请求到服务端,最常见的是新增时插入重复数据,这个问题该怎么办呢?

  • 查询是"12345",至少会请求5次导致频繁查询数据库
  • 有没有一种方法,可以隔个几百毫秒再去查询呢?(setTimeout)
  • 有没有更加高级的做法,用户输入完成后,停顿了几百毫秒再去查询呢?(debounce)
  • 有没有用户体验更加好的做法,不用等待漫长的等待时间从而响应更快呢?(throttle)
  • 快速点击2次,3次,...n次新增按钮导致插入重复数据
  • 如何避免用户单位时间内频繁点击按钮导致重复发送请求的问题?(debounce)
  • 有没有除了debounce之外的更加精准的方法?(loading)
  • debounce适用场景
  • throttle适用场景
  • debounce和throttle的对比
  • 手写一个debounce和throttle(setTimeout版本)
  • 手写一个throttle(不能使用setTimeout)

查询是"12345",至少会请求5次导致频繁查询数据库

<template>
  <input @input="handleInput"/>
</template>

<script>
export default {
  name: 'input',
  data() {
    return {
      delay: 1000,
      count: 0,
    };
  },
  methods: {
    handleInput(e) {
      console.log(`debounce wait时间为${this.delay}ms`);
      console.log('触发了input事件', e.target.value);
      this.count++;
      console.log(`触发了${this.count}次远程搜索`);
    },
  },
};
</script>

打印结果:

debounce wait时间为1000ms 触发了input事件 1 触发了1次远程搜索

debounce wait时间为1000ms 触发了input事件 12 触发了2次远程搜索

debounce wait时间为1000ms 触发了input事件 123 触发了3次远程搜索

debounce wait时间为1000ms 触发了input事件 1234 触发了4次远程搜索

debounce wait时间为1000ms 触发了input事件 12345 触发了5次远程搜索

说明:输入5个数查询5次,造成了频繁查询数据库的行为,是一种性能浪费。

有没有一种方法,可以隔个几百毫秒再去查询呢?(setTimeout

有,可以为函数设置一个setTimeout函数,相当于定时调用接口,这种方法是低效的,也是非常愚蠢的,需要控制开关定时器,一旦搜索功能多了,就更蠢了。

有没有更加高级的做法,用户输入完成后,停顿了几百毫秒再去查询呢?(debounce

有,debounce(防抖)就是做这个事情的,lodash从0.1.0就支持了这个方法。

<template>
  <input @input="debounceHandleInput"/>
</template>

<script>
import _ from 'lodash';

export default {
  name: 'input-debounce',
  data() {
    return {
      delay: 1000,
    };
  },

打印结果: debounce wait时间为1000ms 触发了input事件 12345

说明:在1000ms时间范围内触发,仅仅触发了一次远程搜索,也就是仅仅调用一次后端接口,达到我们的预期效果。

有没有用户体验更加好的做法,不用等待漫长的等待时间从而响应更快呢?(throttle

<template>
  <input @input="throttleHandleInput"/>
</template>

<script>
import _ from 'lodash';

export default {
  name: 'input-throttle',
  data() {
    return {
      delay: 1000,
      count: 0,
    };
  },
  computed: {
    throttleHandleInput() {
      return _.throttle(this.handleInput, this.delay);
    },
  },
  methods: {
    handleInput(e) {
      console.log(`throttle wait时间为${this.delay}ms`);
      console.log('触发了input事件', e.target.value);
      this.count++;
      console.log(`触发了${this.count}次远程搜索`);
    },
  },
};
</script>

打印结果:

throttle wait时间为1000ms 触发了input事件 1 触发了1次远程搜索

throttle wait时间为1000ms 触发了input事件 12345 触发了2次远程搜索

说明:在1000ms时间范围内触发,仅仅触发了2次远程搜索,调用2次后端接口。用户首次输入1立即返回数据,保证数据到达速度,也提升了用户体验。中间的12,123,1234被节流函数成功拦截避免触发。而12345是我们最终需要的搜索结果,在最后返回给用户。达到我们的预期效果。

快速点击2次,3次,...n次新增按钮导致插入重复数据

<template>
  <button @click="handleClick">新增</button>
</template>

<script>
export default {
  name: 'click',
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    handleClick(e) {
      console.log('触发了click事件', e.target.value);
      this.count++;
      console.log(`触发了${this.count}次新增数据`);
    },
  },
};
</script>

触发了click事件 触发了1次新增数据 触发了click事件 触发了2次新增数据

说明:快速点击2次“新增”按钮,而最终只触发了2次数据新增,造成重复数据插入。

如何避免用户单位时间内频繁点击按钮导致重复发送请求的问题?(debounce

<template>
  <button @click="debounceHandleClick">新增</button>
</template>

<script>
import _ from 'lodash';

export default {
  name: 'click-debounce',
  data() {
    return {
      delay: 1000,
      count: 0,
    };
  },
  computed: {
    debounceHandleClick() {
      return _.debounce(this.handleClick, this.delay);
    },
  },
  methods: {
    handleClick(e) {
      console.log(`debounce wait时间为${this.delay}ms`);
      console.log('触发了click事件', e.target.value);
      this.count++;
      console.log(`触发了${this.count}次新增数据`);
    },
  },
};
</script>

打印结果: debounce wait时间为1000ms 触发了click事件 触发了1次新增数据

说明:快速点击2次“新增”按钮,而最终只触发了1次数据新增,达到了我们的预期效果。

有没有除了debounce之外的更加精准的方法?(loading

loading是指在异步请求完成(成功或者失败)前,开启loading,使得按钮或者用户界面处于“加载中”“转圈”“spin"这样的一个状态,从而禁止用户发起重复操作,异步请求完成后,关闭loading。

<template>
  <Button @click="loadingHandleClick" :loading="loading">新增</Button>
</template>

<script>
export default {
  name: 'click-loading',
  data() {
    return {
      loading: false,
      count: 0,
    };
  },
  methods: {
    loadingHandleClick(e) {
      this.loading = true;
      this.count++;
      console.log(`触发了${this.count}次新增数据`);
      console.log('发起异步请求,loding为:', this.loading);
      setTimeout(() => {
        console.log('异步请求执行了1s');
        this.loading = false;
        console.log('异步请求完成,loding为:', this.loading);
      }, 1000);
    },
  },
};
</script><template>
  <Button @click="loadingHandleClick" :loading="loading">新增</Button>
</template>

<script>
export default {
  name: 'click-loading',
  data() {
    return {
      loading: false,
      count: 0,
    };
  },
  methods: {
    loadingHandleClick(e) {
      this.loading = true;
      this.count++;
      console.log(`触发了${this.count}次新增数据`);
      console.log('发起异步请求,loding为:', this.loading);
      setTimeout(() => {
        console.log('异步请求执行了1s');
        this.loading = false;
        console.log('异步请求完成,loding为:', this.loading);
      }, 1000);
    },
  },
};
</script>

触发了1次新增数据 发起异步请求,loding为: true 异步请求执行了1s 异步请求完成,loding为: false

说明:第1次事件触发后,按钮处于loading为true状态,禁止用户触发,1秒后异步请求执行完成,loading为false,允许用户再次使用。因此都无法做到快速点击2次“新增”按钮,只能触发1次,重复的第2次触发用户无法触发,最终只触发了1次数据新增,达到了我们的预期效果。

debounce适用场景

  • Debouncing a click evnet to insert an uniq data
  • Debouncing a input event handler (this example explain this use case)
  • Debouncing a resize event handler

throttle适用场景

  • Throttling a input event handler (this example explain this use case)
  • Throttling a scroll event in infinite scroll(demo case)
  • Throttling a mousemove/touchmove event handler in canvas

debounce和throttle的对比 

  • debounce只有当连续事件停止后的一小段时间后再触发一次,连续事件结束后可能只触发一次。例如,一连串点击、尺寸变化,停止变化时,等待防抖时间,取最近的一次变化。
  • throttle会在连续事件的过程中,每隔一段时间至少触发一次,连续事件结束后触发不止一次。例如,一连串点击,尺寸变化,无需等待停止变化,间隔节流时间,取中间的几次变化。

本文出处:

如何理解debounce(防抖)和throttle(节流)? - 知乎 (zhihu.com)

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

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

相关文章

2023-5-17-CPU架构学习(amd、ard等)

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

Redis高可用性详解

目录 ​编辑 高可用性&#xff1a; 主从复制&#xff08;Master-Slave Replication&#xff09;&#xff1a; 主从复制的一般工作流程&#xff1a; 哨兵模式&#xff08;Sentinel Mode&#xff09;&#xff1a; 哨兵模式的一般工作流程&#xff1a; 集群模式&#xff08…

【大数据学习篇7】 热门品类Top10分析

在HBase命令行工具中执行“list”命令&#xff0c;查看HBase数据库中的所有数据表。学习目标/Target 掌握热门品类Top10分析实现思路 掌握如何创建Spark连接并读取数据集 掌握利用Spark获取业务数据 掌握利用Spark统计品类的行为类型 掌握利用Spark过滤品类的行为类型 掌握利用…

梯度消失和爆炸问题

一、为什么会产生梯度消失和梯度爆炸&#xff1f; 目前优化神经网络的方法都是基于BP&#xff0c;即根据损失函数计算的误差通过梯度反向传播的方式&#xff0c;指导深度网络权值的更新优化。其中将误差从末层往前传递的过程需要链式法则&#xff08;Chain Rule&#xff09;的…

自定义mysql函数之字符串逗号分割查询(find_in_set)

增强 find_in_set() 在mysql中&#xff0c;我们有时候设计数据库某个字段需要通过逗号进行分割&#xff0c;然后根据传入的字符串查询是否存在的方法进行判断&#xff0c;mysql默认的 find_in_set() 可以对比某个逗号分割的字符串中是否存在指定字符串&#xff0c;例如下面的例…

小程序技术,打开跨端管理的思路,提高客户满意度和忠诚度

小程序容器作为跨端管理的有效工具&#xff0c;已经成为越来越多企业的选择。通过小程序容器&#xff0c;企业可以实现跨平台部署&#xff0c;提供一致的用户体验&#xff0c;整合多种渠道实现全渠道协同&#xff0c;进行个性化营销&#xff0c;以及通过数据分析和监控等手段优…

手把手教你,用Auto-GPT自动写个网站(保姆级)

目录 一、什么是 Auto-GPT 二、用Auto-GPT自动给我实现了一个网站 1、运行过程 2、执行任务 3、运行结果 三、如何安装使用&#xff1f;怎么玩 1、注册OpenAI的账号&#xff0c;并获取key 2、下载Git和Python3&#xff08;无脑安装&#xff09; 3、克隆仓库到本地 4、…

【SVN】SVN常用操作

1、svn客户端安装 下载地址&#xff1a;https://tortoisesvn.net/downloads.zh.html 下SVN客户端及汉化包 &#xff08;根据提示安装即可&#xff09; 2、检查是否安装成功 在空白处&#xff0c;右键&#xff0c;可见TortoiseSVN&#xff0c;如下图所示 3、检出&#xff…

React Antd Typescript开发碰到的问题 DatePicker Radio should update 后端数据回显

需求&#xff1a; DatePicker控件 离职人员默认显示后端传过来的离职时间 有两种类型页面&#xff0c;编辑时可操作&#xff0c;详情时不可操作 进入编辑页面时&#xff0c;状态切换成在职时&#xff0c;清空离职时间框且离职时间框不可用&#xff0c;字段设置为 undefined 状态…

国际top5功能完善在线投资平台app软件最新排名(综合评测)

如今&#xff0c;随着科技的发展&#xff0c;越来越多的人选择使用在线投资app软件来进行投资。但是面对众多的选择&#xff0c;选择一款靠谱的在线投资app软件是非常重要的。首先&#xff0c;我们需要考虑该软件的安全性。投资是一项涉及资金的活动&#xff0c;因此&#xff0…

高精度示波器keysight是德DSOS054、MSOS054销售回收

安捷伦Keysight DSOS054A MSOS054 500MHZ高清晰度示波器 特征&#xff1a; 带宽&#xff1a;500 MHz&#xff0c;具有平坦的频率响应&#xff0c;可实现高信号保真度 频道&#xff1a;4 最大存储深度&#xff1a;800 Mpts&#xff08;2 通道&#xff09;&#xff0c;400 Mpt…

新工匠精神是啥

给工匠精神加入新的“工程师”文化 工程化是现代制造的内核 工程师是工程文化的承载人 趣讲大白话&#xff1a;新工匠精神&#xff0c;新在哪里&#xff1f; 【趣讲信息科技170期】 **************************** 工程师文化起源于硅谷 传承工匠精神的&#xff0c;也要加入工程…

本科生高薪专业top10,全被计算机承包了

在每年被唱衰的行业里&#xff0c;即使如高薪神话的IT行业&#xff0c;也难逃此“劫”——IT不行了&#xff01;疲软了&#xff01;现在再入行IT和计算机就是坑&#xff01; 然而事实上&#xff0c;根据最新数据报告显示&#xff0c;2022届本科毕业生毕业半年后月收入排前10位的…

Linux|minio对象存储服务的部署和初步使用总结

前言&#xff1a; minio是一个非常轻量化的对象存储服务&#xff0c;是可以算到云原生领域的。 该服务是使用go语言编写的&#xff0c;因此&#xff0c;主文件就一个文件&#xff0c;它的下载&#xff0c;部署什么的都是非常简单的&#xff0c;一般两三步就可以搭建好了&…

Word控件Spire.Doc 【文本框】教程(6):如何在文本框中设置文本方向

Spire.Doc for .NET是一款专门对 Word 文档进行操作的 .NET 类库。在于帮助开发人员无需安装 Microsoft Word情况下&#xff0c;轻松快捷高效地创建、编辑、转换和打印 Microsoft Word 文档。拥有近10年专业开发经验Spire系列办公文档开发工具&#xff0c;专注于创建、编辑、转…

腾讯的这道公益「微光」,竟已燎原了

台上开发者们的陆续发言&#xff0c;瞬间把我带到了公益的海洋中。谁都不愿放弃追随那道光&#xff0c;那道热爱公益的光&#xff0c;那道为了解决弱势群体难题与时俱进的光&#xff0c;那道为了文化传承的创新之光。这就是第三届Light•技术公益创造营项目路演现场带给我的直观…

若依框架语言国际化操作流程?

国际化是指将产品、服务、企业或组织的活动适应不同国家、不同文化背景和不同语言环境的过程。它包括将产品或服务适应不同的市场需求、文化习惯和法律法规等方面的工作。国际化的目的是拓展企业或组织的市场,提高竞争力和盈利能力。 目录 一、前端国际化流程 1、html使用…

Gradle接入checkstyle代码风格检查插件

一、什么是checkstyle 在项目开发的过程中&#xff0c;代码规范是经常被提起的话题&#xff0c;特别是当项目需要多个开发协同完成的时候&#xff0c;良好统一的代码规范能够在一定程度上保证项目代码的质量和团队的开发效率。目前业界常见代码检查工具有 Alibaba Java Coding…

二分查找的总结

一、二分查找 1.思路分析 这道题目的前提是数组为有序数组&#xff0c;同时题目还强调数组中无重复元素&#xff0c;因为一旦有重复元素&#xff0c;使用二分查找法返回的元素下标可能不是唯一的&#xff0c;这些都是使用二分法的前提条件&#xff0c;当大家看到题目描述满足如…

Ampere Computing 发布全新 AmpereOne 系列处理器,192 个自研核

2023 年 5 月 19 日&#xff0c;中国北京——Ampere Computing 宣布推出全新 AmpereOne™ 系列处理器&#xff0c;该处理器拥有多达 192 个单线程 Ampere 核&#xff0c;内核数量为业界最高。这是第一款基于 Ampere 新自研核的产品&#xff0c;由 Ampere 自有 IP 全新打造。 致…