Underscore.js for easy performance wins

It pays to be smart about interpreting a user’s actions.

The scroll event has become an increasingly popular way for users to view and manipulate the content they see. I think this probably has to do with the barrier between mobile and web breaking down, but also with the prevalence of sites that make brilliant use of parallax techniques. Apple’s one-page overview of the new iPhone 5c, for example, depends solely on a user scrolling the page to fire all of its cool features.

A scroll event occurs on the window object (or on any scrollable element) when the scroll position changes, regardless of the cause or amount. A mouse click or drag on the scroll bar, dragging inside the element, pressing the arrow keys, or using the mouse's scroll wheel all trigger the scroll event. If you bind a handler to the scroll event, that handler will potentially be called dozens of times per second, or more. This can be a drag on performance. Setting a timeout on the scroll handler or using setInterval have been popular fixes, but underscore.js offers a couple even easier ways: _.throttle and _.debounce.

Underscore.js is a utility-belt library. It adds a lot of functions and helpers to JavaScript to facilitate using it for things that other languages do, like map, select, invoke, etc. It also includes a lot of really useful shortcuts.

Underscore’s throttle function looks like this:

_.throttle(function, wait, [options]);

and it’s ideal for handling scroll events. Say you have a function called “updatePosition” that you need to call when a user scrolls the page. Pass that function to _.throttle along with a wait time of, say, 100ms:

var throttled = _.throttle(updatePosition, 100);

Now bind the new throttled version of the function to the window scroll event:

var throttled = _.throttle(updatePosition, 100);

A tenth of a second won’t seem like much time to a user, but it will improve performance considerably.

Another useful Underscore function in the same vein is _.debounce, which looks similar:

_.debounce(function, wait, [immediate]);

Instead of only calling your function every n seconds, _.debounce will wait until n seconds have passed since the last time it was called before calling it again. A good use case for this is if you want to wait until a user has stopped scrolling to trigger an action. I also find it useful in layouts that are highly responsive, when things need to update if the width of the screen changes. In this case, you can bind a debounced function to the window’s resize event so your updates only happen when the new screen size has been reached.

var debouncedLayout = _.debounce(updateLayout, 300);

Both _.throttle and _.debounce take options that have to do with whether your original function is called on the leading edge or the trailing edge of the wait time. If you wanted to prevent accidental double clicks on a submit button, for example, you could attach the debounced submit handler to the leading edge of that click event.

While it’s true that both of these methods can be accomplished in not too many lines using plain JavaScript, Underscore (4.9kb minified, btw) brings so many useful tools that you might just be tempted to include it in your project anyway. So save yourself some time, then go eat a donut, or some jellybeans. That’s what I would do.