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.
debounce
functionDebouncing 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.
throttle
functionWhile 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 true
. setTimeout
takes the responsibility of assigning a variable to throttled
after the wait time has expired.
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.
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>
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!
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.
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 — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
One Reply to "How to debounce and throttle in Vue"
Nice article!
But also is possible to create debounced/throttled method in “methods” options
“`
{
…,
methods: {
debouncedMethod: debounce((event) => {
/*
Here is some logic
*/
}, 1000)
},
…,
}
“`