快捷搜索:  汽车  科技

bounce和boost耐久度(如何理解debounce防抖和throttle)

bounce和boost耐久度(如何理解debounce防抖和throttle)说明:在1000ms时间范围内触发,仅仅触发了一次远程搜索,也就是仅仅调用一次后端接口,达到我们的预期效果。<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); }

bounce和boost耐久度(如何理解debounce防抖和throttle)(1)

前端工程师们都听过看起来很高级的词,节流和防抖,其实节流就是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的对比
查询是"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 }; } 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

说明:在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。

bounce和boost耐久度(如何理解debounce防抖和throttle)(2)

<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的对比

地址:http://demo.nimius.net/debounce_throttle/ 图片:

bounce和boost耐久度(如何理解debounce防抖和throttle)(3)

通过在canvas上连续触发mousemove事件我们发现:

  • debounce只有当连续事件停止后的一小段时间后再触发一次,连续事件结束后可能只触发一次
  • throttle会在连续事件的过程中,每隔一段时间至少触发一次,连续事件结束后触发不止一次

期待和大家交流,共同进步:

大大大前端 / excellent_developers

努力成为优秀前端工程师!

猜您喜欢: