You are currently viewing How to Debounce Scroll Events in Vanilla JavaScript
debounce scroll events

How to Debounce Scroll Events in Vanilla JavaScript

Scroll events are fired at an incredibly high rate—potentially dozens of times per second. If you’re running any complex logic on each scroll (like calculating positions, loading new content, or triggering animations), your app can quickly become sluggish. That’s where debouncing comes in.

In this blog post, we’ll walk you through how to debounce scroll events in vanilla JavaScript. We’ll break down what debouncing is, why it’s useful, and how you can implement it effectively—without relying on any libraries like Lodash or jQuery.

Let’s get started.


What is Debouncing?

Debouncing is a programming technique used to control how often a function is executed over time. In the context of scroll events, it ensures your function doesn’t fire repeatedly, but rather only once after a user has stopped scrolling for a specified duration.

Without debouncing:

javascript
window.addEventListener('scroll', () => {
console.log('Scroll event triggered!');
});

This code will log messages dozens (even hundreds) of times per second as the user scrolls. This can be very inefficient and may cause performance issues.

With debouncing, we delay the execution of the event handler until the scroll has stopped for a specific time (like 100 or 200 milliseconds).


Why Debounce Scroll Events?

Here are a few reasons why you should debounce scroll events in vanilla JavaScript:

  • Improves performance: Especially on slower devices or large pages.

  • Avoids layout thrashing: Frequent DOM reads and writes can lead to janky behavior.

  • Reduces CPU usage: Less load on the browser means smoother user experiences.

  • Avoids redundant calls: You don’t want to run heavy functions dozens of times unnecessarily.


How to Debounce Scroll Events in Vanilla JavaScript

Let’s now walk through how to debounce scroll events in vanilla JavaScript using a simple, reusable debounce function.

Step 1: Write a Debounce Function

Here’s a basic implementation:

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

How It Works:

  • clearTimeout(timeoutId) cancels the previously scheduled execution.

  • setTimeout() schedules a new execution after the delay.

  • func.apply(this, args) ensures the function keeps the correct this context and receives all arguments.


Step 2: Use Debounce with Scroll Event

Now let’s debounce a function that logs scroll positions:

javascript
function handleScroll() {
console.log('User finished scrolling at Y:', window.scrollY);
}
const debouncedScroll = debounce(handleScroll, 200);

window.addEventListener(‘scroll’, debouncedScroll);

Now, handleScroll only fires once the user stops scrolling for 200ms.


Practical Example: Lazy Load Content on Scroll

Let’s see a practical example of how to debounce scroll events in vanilla JavaScript. We’ll create a scenario where content is lazily loaded once scrolling stops.

HTML:

html
<div id="content" style="height: 3000px; padding: 20px;">
Scroll down to load more...
</div>

JavaScript:

javascript
function loadMoreContent() {
const content = document.getElementById('content');
const newElement = document.createElement('p');
newElement.textContent = 'New content loaded after scrolling!';
content.appendChild(newElement);
}
const debouncedLoad = debounce(loadMoreContent, 300);

window.addEventListener(‘scroll’, () => {
if (window.scrollY + window.innerHeight >= document.body.scrollHeight100) {
debouncedLoad();
}
});

This ensures new content is only loaded after the user stops scrolling near the bottom of the page.


Debounce vs Throttle

You might have heard of both debouncing and throttling in JavaScript. While they are related, they serve different purposes:

  • Debounce: Delays execution until after a pause.

  • Throttle: Ensures execution happens at regular intervals, regardless of how often the event is triggered.

If you need precise spacing (e.g., every 100ms during scrolling), use throttle. If you want to execute only after scrolling stops, use debounce.


Advantages of Debouncing in Vanilla JavaScript

Using a debounce function in vanilla JavaScript (instead of a library) offers several benefits:

  • No dependencies: Lightweight and perfect for projects without frameworks.

  • Better control: You can customize the debounce logic to suit your needs.

  • Performance-optimized: Avoid unnecessary computations during rapid events.

  • Browser-friendly: Works in all modern browsers.


Common Use Cases for Debouncing Scroll Events

Understanding how to debounce scroll events in vanilla JavaScript opens up several practical use cases:

  1. Lazy loading images

  2. Infinite scrolling pagination

  3. Scroll-based analytics tracking

  4. Sticky headers visibility toggles

  5. Parallax animations


Bonus: Reusable Debounce Utility

You can improve code reusability by turning the debounce function into a utility:

javascript
// debounce.js
export function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}

Now you can import and use it across multiple scripts in your vanilla JS project.


Use with setAttribute Example

You can also debounce DOM updates like setting attributes. Let’s say you want to dynamically update an element’s attribute after scrolling:

javascript
function updateElementAttribute() {
const el = document.getElementById('banner');
el.setAttribute('data-scrolled', 'true');
}
const debouncedUpdate = debounce(updateElementAttribute, 200);
window.addEventListener(‘scroll’, debouncedUpdate);

If you’re not familiar with setAttribute(), check out our JavaScript setAttribute() example guide to learn more.


Best Practices When Debouncing Scroll Events

Here are some tips to make the most out of debouncing in JavaScript:

  • Choose the right delay: 100-300ms is typical; shorter for faster responsiveness, longer for heavier tasks.

  • Avoid memory leaks: Always clear event listeners when not needed.

  • Test across devices: Scroll performance can vary greatly between desktop and mobile.

  • Measure performance: Use Chrome DevTools to monitor scroll FPS and responsiveness.


Debugging Tip: Add Visual Feedback

Sometimes it helps to visualize the debounce trigger. Add some CSS or log markers to see when the debounced function actually runs:

javascript
function showTrigger() {
console.log('Debounced function triggered at', new Date().toLocaleTimeString());
}
const debouncedVisual = debounce(showTrigger, 250);
window.addEventListener(‘scroll’, debouncedVisual);

This helps you fine-tune the debounce delay during development.


Final Thoughts

Learning how to debounce scroll events in vanilla JavaScript is essential for writing modern, performance-optimized code. It allows you to run expensive functions like DOM manipulations, API calls, or complex animations only when needed.

Here’s what you learned:

  • What debouncing is and why it’s crucial

  • How to implement a debounce function

  • How to use it for scroll events in plain JavaScript

  • Real-world use cases and best practices

By using debouncing correctly, you’ll build web apps that are faster, more efficient, and deliver a smoother user experience.


Ready to Optimize Your Web Performance?

Now that you know how to debounce scroll events in vanilla JavaScript, explore more ways to enhance your frontend skills. For example, you can learn how to update DOM attributes dynamically with our JavaScript setAttribute() example guide.

Leave a Reply