November 12, 2024

Avoid Excessive Requests with Debounce

When developing web applications, it's common to need to make backend requests while users enter data in text fields, such as in a search box. While this isn't a problem in applications with low traffic, the situation changes dramatically in systems handling thousands of simultaneous users. In these cases, each keystroke could generate a request that interacts with the database, which can cause serious performance issues.

To solve this, we need to implement a mechanism that controls the frequency of requests. Instead of creating an algorithm from scratch, we can use a proven and efficient technique known as debounce, which allows us to manage these requests optimally.

Debounce works like a smart timer that waits for the user to finish typing before executing the action. For example, if we set a wait time of 500 milliseconds, the debounce function:

  1. Detects the first keystroke but doesn't execute the request immediately
  2. Starts a 500ms timer
  3. If the user presses another key before the time expires, it resets the timer
  4. Only when the user stops typing and 500ms have passed, the request is finally executed

This means that if a user quickly types "programming", instead of making 12 requests (one for each letter), only one request will be executed with the complete word.

Let's look at a practical implementation example:

function debounce(func, wait) {
  let timeout;
  return function executedFunction(...args) {
    const later = () => {
      clearTimeout(timeout);
      func(...args);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}
// Usage example
const searchProducts = debounce((text) => {
  // Make backend request
  console.log('Searching:', text);
}, 500);
// In the search field
searchInput.addEventListener('input', (e) => {
  searchProducts(e.target.value);
});

With this technique, we achieve a better user experience and reduce the load on our servers by minimizing unnecessary requests.