Javascript Scroll Events (Doing it Right)

The javascript scroll event is quite useful, but used poorly it can harm performance and annoy your users. If the following code snippet looks familiar, you should probably keep reading.

scrollHandler = function(){
	//Do some stuff
    console.log(++i);
} 
window.onscroll = scrollHandler;

The Problem

In the above example, the scroll handler function is executed every time the scroll event is fired. As it  turns out, the scroll event is fired a lot. It can be called hundreds of times in a matter of seconds. The following video demonstrate just how often it is fired.

In the example, the executed code is quite simple, it just logs i++. More complicated code, especially something that causes a repaint, can cause huge performance issues.

The Solution

The browser controls the scroll event, making it impossible to change the frequency at which it is fired. Instead, techniques are used to change the frequency at which the code is executed. Both common approaches using this sort of thinking.

Debouncing

In debouncing, the code is not executed until the event has not been fired for a set amount of time. In practice, this means the code will not be executed until the user has stopped scrolling.

The following code snippet is my take at a debounce function. The video uses the same function and demonstrates the functionality of debouncing.

function debounce(callback, wait) {
	var time;
	return function() {
		clearTimeout(time);
		time = setTimeout(function() {
			time = null;
			callback.call();
		}, wait);
	}
}
scrollHandler = debounce(function(){
	console.log(++i);
}, 100);
window.onscroll = scrollHandler;

The debouncing approach proves an amazingly efficient method for handling scroll events. It is the obvious choice if the code execution can wait until the user has stopped scrolling. For some effects, where debouncing just won’t cut it, throttling should be used.

Throttling

In throttling, the code execution is limited to once in a specified time period. Instead of being executed 100 times in a second, it may only be executed 4 or 5 times (depending on configuration).

Again, the following code snippet is my take on a throttling function and the video demonstrates its functionality.

function throttle(callback, wait) {
	var time,
	go = true;
	return function() {
		if(go) {
			go = false;
			time = setTimeout(function(){
				time = null;
				go = true;
				callback.call();
			}, wait);
		}
	}
}
scrollHandler = throttle(function(){
	console.log(++i);
}, 250);
window.onscroll = scrollHandler;

TL;DR

Throttling or debouncing should be used when attaching code execution to the scroll event. Doing So will increase performance and provide a better user experience.