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

在做远程搜索时,如果每输入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次,造成了频繁查询数据库的行为,是一种性能浪费。

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

有没有一种方法,可以隔个几百毫秒再去查询呢?(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,};},computed: {debounceHandleInput() {return _.debounce(this.handleInput, this.delay);},},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事件 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>

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

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

手写一个debounce

function debounce(fn, delay){let timer;return function(){const _this = this;const args = arguments;if(timer) clearTimeout(timer);timer = setTimeout(()=>{fn.apply(_this, args); // _this.fn(args);}, delay)}
}

手写一个throttle

function throttle(fn, delay){let timer;return function(){const _this = this;const args = arguments;if(timer) return;timer = setTimeout(()=>{fn.apply(_this, args); // _this.fn(args);timer = null;}, delay)}
}

手写一个throttle(不能使用setTimeout)

function throttle(fn, delay){let lastTime = 0;return function(){const _this = this;const args = arguments;const currentTime = Date.now();if(currentTime - lastTime > delay){fn.apply(_this, args);lastTime = currentTime}}
}
let fn = (e,data)=>{console.log(e, e.offsetX, e.offsetY, data)}
let throttleFn = throttle(fn, 2000)
document.onmousemove = function(e){throttleFn(e, 'throttle')
}

如何理解debounce(防抖)和throttle(节流)?相关推荐

  1. 每日源码分析 - lodash(debounce.js和throttle.js)

    本系列使用 lodash 4.17.4 前言 本文件引用了isObject函数 import isObject from './isObject.js' 判断变量是否是广义的对象(对象.数组.函数), ...

  2. 函数防抖 和 函数节流

    函数防抖 和 函数节流 函数防抖(debounce) 概念 函数防抖 就是指 触发事件后 在 n 秒内 函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间. 简单的说,当一个动作 ...

  3. js中的函数防抖和函数节流

    1.什么是函数防抖和函数节流 防抖(debounce)和节流(throttle)都是用来控制某个函数在一定时间内执行多少次的技巧,两者相似不相同,基本思想都是某些代码不可以在没有间断的情况下连续重复执 ...

  4. JS高级 之 防抖 debounce - throttle 节流

    目录 一.防抖 debounce 1. 概念 2. 应用场景 3. 使用 underscore 实现防抖 01 - 代码 02 - 效果 4. 实现 01 - 基本实现 代码 效果 02 - 优化 = ...

  5. 函数防抖和函数节流原理理解

    防抖和节流有什么用,一般的使用场景,原理是什么 1.作用 使用函数节流与函数防抖的目的,就是为了节约计算机资源,提升用户体验. 2.场景 节流一般是用在必须执行这个动作,但是不能够执行太频繁的情况下, ...

  6. 函数防抖和函数节流的最简单解释

    函数防抖:连续触发的事件,只会触发最后一次.每次触发的时候都会清除上一次待触发的. const debounce = (func, wait) => {let timer;return (par ...

  7. 微信小程序 函数防抖和函数节流

    函数防抖:延迟函数执行,多用于input框输入时,显示匹配的输入内容的情况 函数节流:单位时间n秒内,第一次触发函数执行 之后不管触发多少次都不执行.到下一个单位时间n秒时 第一次触发函数执行,多用于 ...

  8. 防抖函数和节流函数的实现,这个是在某保险公司笔试题遇到的。

    scroll 事件本身会触发页面的重新渲染,同时 scroll 事件的 handler 又会被高频度的触发, 因此事件的 handler 内部不应该有复杂操作,例如 DOM 操作就不应该放在事件处理中 ...

  9. debounce 防抖函数

    /*** 防抖* @param fn 防抖包裹的函数* @param delay 延迟时间* @param option 配置* @param {Boolean} immediate 是否在高频事件触 ...

最新文章

  1. 17.SpringMVC核心技术-拦截器
  2. springboot整合mybatis和mybatis-plus
  3. 大数据量传输时配置WCF的注意事项
  4. java的mock测试框架
  5. android行高,android – GridView的行高
  6. BZOJ 2734 [HNOI2012]集合选数 (状压DP、时间复杂度分析)
  7. linux如何利用命令保存文件,如何在Linux中将命令输出保存到文件?
  8. gerber文件怎么导贴片坐标_利用Gerber文件生成贴片坐标及元件位置图的方法技巧...
  9. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第8篇]交互式的定义如何帮助计算和IP类问题是什么
  10. MySQL 存储引擎 | MyISAM 与 InnoDB
  11. hdu 6086 -- Rikka with String(AC自动机 + 状压DP)
  12. php的联查,PHP的多表联查
  13. cygwin的安装使用
  14. iOS - OC 与 Swift 互相操作
  15. Windows API一日一练(40)CreateRectRgn和CombineRgn函数
  16. 偏差、误差、训练误差、测试误差
  17. 物联网碎片化的一些思考
  18. CSDN版主考核方案
  19. 机房收费系统(二)之下机退卡
  20. 计算机考研多少是高分,考研多少分算高分 总分500考380难吗

热门文章

  1. BaiduMap---百度地图官方Demo之路径规划功能(介绍公交,驾车和步行三种线路规划方法和自设路线方法)
  2. C# 线程锁和单多线程简单使用
  3. jdk重新安装需要卸载吗_linux卸载jdk并重新安装
  4. Excel输入公式后只显示公式却不计算如何解决?
  5. 代替YCM,当前vim最强自动补全方案
  6. 超详细的纯净windows系统重装示例
  7. 小米网站主页面大模块——小模块+导航(浮动案例)
  8. 心里话python_一个老运维的心里话
  9. JavaScript-移动端(touch事件)
  10. vue移动端touch事件