Performance is one of the many things that are prioritized when building websites and software generally. As software engineers, it's imperative that we write code with performance in mind, as this would help a great deal to improve the overall user experience of our software.
In this article, we'd be taking a look at Debouncing, a very useful technique for improving the performance of client-side applications.
Before we look at what debouncing is, let's take a brief look at event listeners.
Event Listeners
When building client-side applications, event listeners are things we can't do without. Every client-side application would require that the user interacts with it for it (the app) to be useful, these interactions could be clicking a button, scrolling to view more content, typing into an input field, submitting a form and so many more. These event listeners have callbacks that fire whenever the event they're listening for is triggered.
On some occasions, these event listeners would have performant-heavy callbacks, hence, the need for us to control how and when these callbacks are called. And this is where debouncing comes to play.
Let's assume that we have a search bar that makes a request to an API whenever a user makes a change to the input field. That means if a user wants to search for the term 'What is debouncing?', the browser would have to make a total of 19 requests to the API.
Here's a code pen so you can test it out.
Now, with this approach, our browser makes a request for every single keystroke the user makes on the keyboard, which leaves us with multiple useless requests.
How about we find a way to prevent the request from being made until the user has finished typing? Would this solve the problem? Now, this is exactly what debouncing is.
Debouncing
Debouncing is a method in which a function is prevented from running until a certain amount of time has elapsed without the function being called. In our case, the request won't be made until the user has stopped typing.
Implementing debouncing, our event callback would look something like this:
let timeout;
// other codes
inputField.addEventListener('input', () => {
clearTimeout(timeout);
timeout = setTimeout(makeRequest, 500);
})
From the above snippet, whenever a user types, we clear a timeout, which does not exist when the function is called initially. We then create another timeout using setTimeout
, which calls the makeRequest
function whenever the time has elapsed. That means that if the timeout has not exceeded and the user types, we clear the previous timer and create another one. This way, only the last timeout would run. Hence, solving our problem of having multiple requests. n
This is what it looks out after implementing debouncing:
Makes more sense, right?
Here's a codepen if you want to take a close look at the implementation
An extra something
Instead of manually writing the debouncing function every time we want to implement this amazing functionality, we can just create a utility function that takes a callback and a timer and then return a function that has the whole debouncing functionality.
Something like this:
function debounce(func, timeINMS) {
let timeout;
return function () {
clearTimeout(timeout);
timeout = setTimeout(func, timeINMS);
};
}
let debouncedHello = debounce(() => console.log("say hello", Date.now()), 800);
Here, the debounce
function takes two arguments, a function that logs say hello
and a number that represents time(in milliseconds) through which the function should be delayed, then returns a function that has the function of debouncing.
Debouncing is a very simple and intuitive technique but also considerably improves performance.
I hope you were able to follow through with the concept. In my next article, I'd be talking about another technique which is a little like debouncing: Throttling.
Stay tuned and stay safe❤✌️
Top comments (18)
Asynchrony is one of the most complex problems in front-end programming, and there is even a super-powerful library like rxjs that deals specifically with async-related issues.
I also maintains its own lightweight lib for handling asynchronous related tasks, refer to @liuli-util/async
I agree with you. RxJS is a pretty cool library and I'd advice anyone who does frontend development to check it out
rxjs is really cool, but I don't think all front-ends have to master rxjs, it's so complicated that most projects don't need to use it, that's why we maintain some similar functions separately and form a lib reason.
Using asynchronous have its own difficulty and creates new problems. One in particular to be aware of is what happens if the objects referenced by the delayed function are no longer valid when it resolves.
Super easy to understand the concept.....and it's use...Good one
I'm happy you understood it... Thanks for reading
TIL! Thanks for this.
You're welcome Jason
I've always thought of debouncing to avoid unnecessary function calls. Your article is quite clear and succinct.
Thanks for reading
Good read! Thank you for the article
Thank you very much Prafful
Great article, thanks.
Thanks for reading Nick
Nicely explained.
Nice post!
Thanks for reading
Nice implementation, I had used a different debounce func before