Front-end engineers have all heard the fancy terms throttle and debounce, but throttling is throttle and debounce is part of front-end performance optimization.

  • Throttling acts as a valve to control the flow of water to avoid excessive flow per unit time
  • Anti – shake to prevent jitter, flow control effect is better than throttling

When doing a remote search, if the interface is called once for every word entered, the database will be queried frequently, assuming our query is “12345”, at least five times regardless of user input errors.

Consider another issue where the button click is triggered repeatedly (e.g., two quick clicks, three quick clicks… N times) how to do a layer of interception in the front end, to avoid sending repeated requests to the server, the most common is to insert duplicate data, this problem how to do?

  • The query is “12345” and will be requested at least 5 times resulting in frequent database queries
  • Is there a way to query every few hundred milliseconds? SetTimeout ()
  • Is there a more advanced way for the user to enter, pause for a few hundred milliseconds, and then query? (debounce)
  • Is there a better user experience that doesn’t require long wait times to respond faster? (throttle)
  • Quick 2 clicks, 3 clicks… Adding a button for n times causes duplicate data to be inserted
  • How to avoid the problem of repeated requests caused by frequent button clicks per unit of time? (debounce)
  • Is there a more precise approach besides Debounce? (loading)
  • Debounce applies to scenarios
  • Throttle Application Scenarios
  • Debounce versus Throttle

The query is “12345” and will be requested at least 5 times resulting in frequent database queries

<template> <input @input="handleInput"/> </template> <script> export default { name: 'input', data() { return { delay: 1000, count: 0, }; }, methods: {handleInput(e) {console.log(' debounce wait time = ${this.delay}ms'); Console. log(' triggered input event ', e.target.value); this.count++; Console. log(' triggered a ${this.count} remote search '); ,}}}; </script>Copy the code

Print result: An input event was triggered. 1 An input event was triggered. 12 Two remote search debounce wait times were triggered An input event was triggered. 123 Three remote search debounce wait times were triggered. 1234 Four remote search Debounce wait times were triggered Triggered five remote searches

Note: Enter 5 numbers to query 5 times, resulting in frequent database query behavior, which is a performance waste.

Is there a way to query every few hundred milliseconds? SetTimeout ()

Yes, you can set a setTimeout function for a function, which is equivalent to a timed call to the interface. This method is inefficient, and also very stupid, need to control the switch timer, once the search function is more stupid.

Is there a more advanced way for the user to enter, pause for a few hundred milliseconds, and then query? (debounce)

Yes, debounce is for this, and LoDash has supported this method since 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 time = ${this.delay}ms'); Console. log(' triggered input event ', e.target.value); this.count++; Console. log(' triggered a ${this.count} remote search '); ,}}}; </script>Copy the code

Output: Debounce Wait time 1000ms triggered the input event 12345

Note: when triggered in the time range of 1000ms, only one remote search is triggered, that is, only one call to the back-end interface, achieving our expected effect.

Is there a better user experience that doesn’t require long wait times to respond faster? (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 time = ${this.delay}ms'); Console. log(' triggered input event ', e.target.value); this.count++; Console. log(' triggered a ${this.count} remote search '); ,}}}; </script>Copy the code

1 you are throttle waiting for 1000ms to trigger the input event. You are throttle waiting for 1000ms to trigger the input event 12345

Note: When triggered in the time range of 1000ms, only two remote searches are triggered and two back-end interfaces are called. Data is returned immediately after the user enters 1 for the first time, which ensures data arrival speed and improves user experience. The middle 12,123,1234 was successfully intercepted by the throttling function to avoid firing. And 12345 is the final search result we want to return to the user at the end. To achieve our desired effect.

Quick 2 clicks, 3 clicks… Adding a button for n times causes duplicate data to be inserted

<template> <button @click="handleClick"> Add </button> </template> <script> export default {name: 'click', data() { return { count: 0, }; }, methods: {handleClick(e) {console.log(' triggered the click event ', e.target.value); this.count++; Console. log(' triggered ${this.count} new data '); ,}}}; </script>Copy the code

The click event triggered 1 new data. The click event triggered 2 new data

Note: Click the “Add” button twice quickly, but only two data additions are triggered, resulting in repeated data insertion.

How to avoid the problem of repeated requests caused by frequent button clicks per unit of time? (debounce)

<template> <button @click="debounceHandleClick"> Add </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 time = ${this.delay}ms'); Console. log(' triggered the click event ', e.target.value); this.count++; Console. log(' triggered ${this.count} new data '); ,}}}; </script>Copy the code

The click event triggered 1 new data to be added

Note: Click the “Add” button twice quickly, but only one data add is triggered in the end, achieving our expected effect.

Is there a more precise approach besides Debounce? (loading)

Loading means to enable loading before an asynchronous request is completed (successfully or failed), so that the button or user interface is in a state such as “loading”, “spinning”, or “spin”. In this way, the user cannot initiate repeated operations. After the asynchronous request is completed, the loading is disabled.

<template> < button@click ="loadingHandleClick" :loading="loading"> Add </Button> </template> <script> export default { name: 'click-loading', data() { return { loading: false, count: 0, }; }, methods: { loadingHandleClick(e) { this.loading = true; this.count++; Console. log(' triggered ${this.count} new data '); Console. log(' initiate asynchronous request,loding is :', this.loading); SetTimeout (() => {console.log(' asynchronous request executed for 1s'); this.loading = false; Console. log(' asynchronous request completed,loding :', this.loading); }, 1000); ,}}}; </script>Copy the code

An asynchronous request for new data is triggered. The loding value is true. The asynchronous request is completed after 1s

Note: After the first event is triggered, the loading state of the button is true, which disables the user to trigger the button. One second later, the asynchronous request is completed, and the loading state is false, allowing the user to use the button again. Therefore, it is impossible to quickly click the “Add” button twice, only one time can be triggered. The user cannot trigger the repeated second time, and finally only one time of data addition can be triggered, achieving our expected effect.

Debounce applies to scenarios

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

Throttle Application Scenarios

  • Throttling a input event handler (this example explains this use case)
  • Throttling a Scroll Event in Infinite Scroll (Demo Case)
  • Throttling a mousemove/touchmove event handler in canvas

Debounce versus Throttle

Address:Demo.nimius.net/debounce_th…Image:

By continuously triggering the Mousemove event on the canvas we find:

  • Debounce is triggered only once after a short period of time after the consecutive event has stopped, and may only once after the consecutive event has ended
  • Throttle fires at least once every period of time during a continuous event and more than once after the continuous event ends

Looking forward to communicating with you and making progress together:

  • excellent_developers

Strive to be an excellent front-end engineer!