Skip to content

Bits of .NET

Daily micro-tips for C#, SQL, performance, and scalable backend engineering.

  • Asp.Net Core
  • C#
  • SQL
  • JavaScript
  • CSS
  • About
  • ErcanOPAK.com
  • No Access
  • Privacy Policy
JavaScript

Debounce vs Throttle in JavaScript: When to Use Which (With Real Examples)

- 01.02.26 | 01.02.26 - ErcanOPAK

Search inputs lagging? Scroll events killing performance? Understanding debounce vs throttle is critical for responsive UIs.

Debounce – Wait Until User Stops:

function debounce(func, delay) {
  let timeoutId;
  
  return function(...args) {
    clearTimeout(timeoutId);
    
    timeoutId = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

// Usage: Search input
const searchInput = document.getElementById('search');

const performSearch = debounce((query) => {
  console.log('Searching for:', query);
  // Actual API call here
  fetch(`/api/search?q=${query}`);
}, 500);

searchInput.addEventListener('input', (e) => {
  performSearch(e.target.value);
});

How Debounce Works:
User types “javascript”:
• j → timer starts (500ms)
• ja → timer resets (500ms from now)
• jav → timer resets again
• java → timer resets
• javas → timer resets
• javasc → timer resets
• javascr → timer resets
• javascri → timer resets
• javascrip → timer resets
• javascript → timer resets
• (user stops typing)
• 500ms passes → API call executes ONCE

Result: 1 API call instead of 10. 90% reduction in server load.

Throttle – Execute at Regular Intervals:

function throttle(func, limit) {
  let inThrottle;
  
  return function(...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      
      setTimeout(() => {
        inThrottle = false;
      }, limit);
    }
  };
}

// Usage: Infinite scroll
const handleScroll = throttle(() => {
  const scrollPosition = window.scrollY + window.innerHeight;
  const pageHeight = document.documentElement.scrollHeight;
  
  if (scrollPosition >= pageHeight - 100) {
    console.log('Load more items');
    loadMoreItems();
  }
}, 200);

window.addEventListener('scroll', handleScroll);

How Throttle Works:
User scrolls continuously for 1 second:
• 0ms: Function executes
• 50ms: Blocked (within 200ms limit)
• 100ms: Blocked
• 150ms: Blocked
• 200ms: Function executes
• 250ms: Blocked
• 300ms: Blocked
• 400ms: Function executes
• 600ms: Function executes
• 800ms: Function executes
• 1000ms: Function executes

Result: 6 executions instead of 60+ (one per scroll event). Still responsive, but 90% less work.

Decision Tree – Which to Use:

// Use DEBOUNCE for:
- Search inputs (wait until user finishes typing)
- Form validation (validate after user stops typing)
- Window resize handling (wait until resize complete)
- Auto-save draft (save after user stops editing)

// Use THROTTLE for:
- Scroll events (infinite scroll, parallax effects)
- Mouse move tracking (drawing, games)
- Button clicks (prevent double-submit)
- API rate limiting (max X requests per second)

Real Performance Impact:

// Without debounce/throttle
searchInput.addEventListener('input', (e) => {
  fetch(`/api/search?q=${e.target.value}`); // Fires on EVERY keystroke
});

// Typing "javascript" = 10 keystrokes = 10 API calls
// At 200ms per request = 2 seconds of unnecessary load
// Multiply by 1000 concurrent users = server meltdown

// With debounce (500ms)
// Typing "javascript" = 1 API call
// 0.2 seconds total
// 90% reduction in server load

Pro Tip – Leading Edge Throttle:
Sometimes you want immediate execution, then throttling:

function throttleLeading(func, limit) {
  let lastRun = 0;
  
  return function(...args) {
    const now = Date.now();
    
    if (now - lastRun >= limit) {
      func.apply(this, args);
      lastRun = now;
    }
  };
}

// Button click: Execute immediately, then block for 2 seconds
const submitButton = document.getElementById('submit');

submitButton.addEventListener('click', throttleLeading(() => {
  console.log('Form submitted!');
  submitForm();
}, 2000));

First click executes instantly (good UX). Subsequent clicks within 2 seconds are ignored (prevent double-submit).

Related posts:

AJAX “POST Suddenly Fails” — The Missing Content-Type Header

JavaScript Timers Drift Over Time

Ajax Calls Block UI Under Load

Post Views: 2

Post navigation

Use HTML Dialog Element for Accessible Modals (Forget JavaScript Libraries)
Handle AJAX Errors Properly: Retry Logic with Exponential Backoff

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

February 2026
M T W T F S S
 1
2345678
9101112131415
16171819202122
232425262728  
« Jan    

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (935)
  • How to add default value for Entity Framework migrations for DateTime and Bool (832)
  • Get the First and Last Word from a String or Sentence in SQL (826)
  • How to select distinct rows in a datatable in C# (799)
  • How to make theater mode the default for Youtube (717)
  • Add Constraint to SQL Table to ensure email contains @ (574)
  • How to enable, disable and check if Service Broker is enabled on a database in SQL Server (553)
  • Average of all values in a column that are not zero in SQL (520)
  • How to use Map Mode for Vertical Scroll Mode in Visual Studio (474)
  • Find numbers with more than two decimal places in SQL (436)

Recent Posts

  • C#: Use MemoryPack for 10x Faster Serialization than JSON
  • C#: Use params ReadOnlySpan for Allocation-Free Variable Arguments
  • C#: Use ObjectPool for Reusing Expensive Objects
  • C#: Use Lazy for Expensive Object Initialization
  • SQL: Use STRING_AGG to Concatenate Rows into Comma-Separated List
  • SQL: Use Filtered Indexes to Index Only Subset of Rows
  • .NET Core: Use Result Pattern to Avoid Exceptions for Expected Errors
  • .NET Core: Use IOptions Pattern for Strongly-Typed Configuration
  • Git: Use .gitattributes to Handle Line Endings Across OS
  • Git: Use git notes to Add Comments to Commits Without Changing History

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (935)
  • How to add default value for Entity Framework migrations for DateTime and Bool (832)
  • Get the First and Last Word from a String or Sentence in SQL (826)
  • How to select distinct rows in a datatable in C# (799)
  • How to make theater mode the default for Youtube (717)

Recent Posts

  • C#: Use MemoryPack for 10x Faster Serialization than JSON
  • C#: Use params ReadOnlySpan for Allocation-Free Variable Arguments
  • C#: Use ObjectPool for Reusing Expensive Objects
  • C#: Use Lazy for Expensive Object Initialization
  • SQL: Use STRING_AGG to Concatenate Rows into Comma-Separated List

Social

  • ErcanOPAK.com
  • GoodReads
  • LetterBoxD
  • Linkedin
  • The Blog
  • Twitter
© 2026 Bits of .NET | Built with Xblog Plus free WordPress theme by wpthemespace.com