Sampath Gajawada I'm a full-stack developer who always wishes to implement new and challenging elements in my daily life. Currently, my focus is on React and Vue.

How to debounce and throttle in Vue

4 min read 1146

Vue Debounce Throttle

When you’re building any type of web application, performance is your main concern, especially for sites that carry interactions. Listening to events like user typing input, scrolling, and resizing may cause the application to become unresponsive when it performs heavy computations or calls an API.

debounce and throttle are two techniques that can slow down these event handlers by limiting the function calls. In this article, we’ll learn how to debounce and throttle watchers and event handlers in a Vue application.

Table of contents

Create a debounce function

Debouncing is a technique that can improve your application’s performance by waiting to trigger an event until a certain amount of time has passed; implementing the debounce function allows a function to wait a set time before running again.

Before jumping into the code, let’s understand the idea behind debouncing. As an example, imagine that a user is typing in a text box, and as the user types, we’d like to fetch data from an API. If we call the API as many times as the user types on their keyboard, the application will create a huge number of network requests, leading to a decrease in performance.

Let’s assume you’d like to debounce a function, in our case, the search function. We set the function to be executed after a certain time period, which is the estimated amount of time that the user leaves the keyboard before typing each new character. If the user is typing within this time frame, we postpone our function call to the next time interval. With this approach, we can reduce the number of function calls within intervals of typing:

Below is the code snippet for the debounce function:

export function debounce(fn, wait){
    let timer;
   return function(...args){
     if(timer) {
        clearTimeout(timer); // clear any pre-existing timer
     }
     const context = this; // get the current context
     timer = setTimeout(()=>{
        fn.apply(context, args); // call the function if time expires
     }, wait);
   }
}

The debounce function takes two arguments, the function to be debounced and the wait time in milliseconds. It returns a function and can be called later:

const debouncedFunction = debounce(function() { ... }, 300);
console.log(typeof debouncedFunction); // `function`
When the debounce function is triggered:

In the code above, we cancel any pre-existing timeout, and we schedule a new timeout based on the specified wait time. When the timeout expires, we call the callback function with arguments.

Create a throttle function

While debounce calls a function when a user has not carried out an event in a specific amount of time, throttle calls a function at intervals of a specified time while the user is carrying out an event.

For example, if we debounce the search function with a timer of 300 milliseconds, the function is only called if the user did not perform a search in 300 milliseconds. However, if we throttle the search function with 300 milliseconds, the function is called every 300 milliseconds as the user is typing.

Below is the code snippet for the throttle function in our example:

export function throttle(fn, wait){
    let throttled = false;
    return function(...args){
        if(!throttled){
            fn.apply(this,args);
            throttled = true;
            setTimeout(()=>{
                throttled = false;
            }, wait);
        }
    }
}

When the throttle function is triggered, the throttled variable is set to false, and the supplied function is called with arguments.

After the function call, we set the throttled variable to true. If any event happens in this specified time, the function is not called until the throttle variable is set to truesetTimeout takes the responsibility of assigning a variable to throttled after the wait time has expired.

Debounce a watcher

Let’s create a simple component where our task is to call the Fetch API and log the value when the user types in a text box:

<template>
 <div id="app">
  <input v-model="value" type="text" />
  <p>{{ value }}</p>
</div>
</template>
<script>
export default {
  data() {
    return {
      value: "",
    };
  },
  watch: {
    value(newValue, oldValue) {
      console.log("value changed: ", newValue, oldValue);
      // call fetch API to get results
    }
  }
};
</script>

In the example above, each time the user types a value, it is logged to the console and the API is called. We can’t call the API so often without degrading the application’s performance. Therefore, we’ll debounce the activity above and call this debounced function inside a watcher. For this, we can use the debounce function, which we created earlier.

Below is the code after debouncing:

<template>
 <div id="app">
  <input v-model="value" type="text" />
  <p>{{ value }}</p>
</div>
</template>
<script>
import {debounce} from "./Utils.js";
export default {
  data() {
    return {
      value: "",
    };
  },
  created(){
     this.debouncedFetch = debounce((newValue, oldValue)=>{
            console.log("value changed: ", newValue, oldValue);
           // call fetch API to get results
     }, 1000);
  },
  watch: {
    value(...args) {
      this.debouncedFetch(...args);
    }
  }
};
</script>

In the code above, the user can log to the console or call the API if 1000 milliseconds has passed since the last typing activity.



We’ll implement debouncing on the watcher by creating an instance of debouncedFetch, which calls the debounce function with a callback and a wait time. This instance is created in the created() Hook, then we invoke the debouncedFetch with the right arguments inside the watcher.

Debounce an event handler

Debouncing the watcher and event handlers are similar. Let’s consider the same example where the user types into a text box. After typing, we’ll log to the console and call the Fetch API.

Below is the example before debouncing:

<template>
  <input v-on:input="onChange" type="text" />
</template>
<script>
export default {
  methods: {
    onChange(event) {
      console.log('changed value', event.target.value);
      // call fetch API to get results
    }
  }
};
</script> 

Now, we’ll debounce the onChange event handler to limit the function calls when the user types.

Inside the created() Hook, create an instance of the debounce function by passing an event handler and a wait time by naming it onChangeDebounced. Then, assign onChangeDebounced to an @input event handler:

<template>
  <input @input="onChangeDebounced" type="text" />
</template>
<script>
import {debounce} from './Utils.js';
export default {
  created() {
    this.onChangeDebounced = debounce(event => {
      console.log('changed value:', event.target.value);
      // call fetch API to get results
    }, 1000);
  },
};
</script>

Conclusion

In this tutorial, we learned about debouncing and throttling the watcher and event handlers in Vue. debounce and throttle are two powerful techniques for improving your application’s performance by limiting function calls to slow down event handlers.

Now that you understand how debounce and throttle work, give it a try in your own project. You should see immediate performance benefits. Leave a comment and let me know how it goes!

Experience your Vue apps exactly how a user does

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - .

Sampath Gajawada I'm a full-stack developer who always wishes to implement new and challenging elements in my daily life. Currently, my focus is on React and Vue.

Leave a Reply