Function Debouncing with Underscore.js

By  on  

The ability to listen and react to user interactions with JavaScript is fundamental and incredibly useful. Some interactions happen frequently and some rarely. Some listener functions are light of action, others can be quite taxing on the browser. Take window's resize event for example: the event fires at each step in the resize, so if you have a taxing event listener, your user's browser will get bogged down quickly.

Obviously we can't allow the user's browser to get bogged down, but we can't simply remove listener function either. What we can do, however, is use debouncing to temper the amount of time the method runs. Instead of the listener function firing on each iteration of the resize event, we can ensure it fires only every n milliseconds during the resize, allowing our functionality to fire but at a rate so as to not ruin the user's experience. A great utility called Underscore.js provides an easy to use method for easily creating debouncing event listener functions.

The JavaScript

Creating a debouncing event listener is as easy as:

// Create the listener function
var updateLayout = _.debounce(function(e) {

	// Does all the layout updating here
}, 500); // Maximum run of once per 500 milliseconds

// Add the event listener
window.addEventListener("resize", updateLayout, false);

..because the Underscore.js code underneath the hood manages the interval checks and original listener function calling:

// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
	var timeout;
	return function() {
		var context = this, args = arguments;
		var later = function() {
			timeout = null;
			if (!immediate) func.apply(context, args);
		var callNow = immediate && !timeout;
		timeout = setTimeout(later, wait);
		if (callNow) func.apply(context, args);

Not the most complex piece of code but nice that you don't have to write it yourself. The debounce method doesn't rely on any other Underscore.js methods, so you can add this method to a framework like jQuery or MooTools quite easily:

// MooTools
	debounce: function(wait, immediate) {
		var timeout, 
		    func = this;
		return function() {
			var context = this, args = arguments;
			var later = function() {
				timeout = null;
				if (!immediate) func.apply(context, args);
			var callNow = immediate && !timeout;
			timeout = setTimeout(later, wait);
			if (callNow) func.apply(context, args);

// Use it!
window.addEvent("resize", myFn.debounce(500));

As mentioned above, window resize events are the most obvious place to use debouncing, but you could also use them for key events that trigger an autocompleter. I love tiny pieces of code like this that can enhance a site's efficiency so quickly! I also recommend you take a look at Underscore.js and the numerous utility functions it provides -- enrich your existing framework or use it as is!

Recent Features

  • By
    Welcome to My New Office

    My first professional web development was at a small print shop where I sat in a windowless cubical all day. I suffered that boxed in environment for almost five years before I was able to find a remote job where I worked from home. The first...

  • By
    5 Awesome New Mozilla Technologies You’ve Never Heard Of

    My trip to Mozilla Summit 2013 was incredible.  I've spent so much time focusing on my project that I had lost sight of all of the great work Mozillians were putting out.  MozSummit provided the perfect reminder of how brilliant my colleagues are and how much...

Incredible Demos

  • By
    CSS 3D Folding Animation

    Google Plus provides loads of inspiration for front-end developers, especially when it comes to the CSS and JavaScript wonders they create. Last year I duplicated their incredible PhotoStack effect with both MooTools and pure CSS; this time I'm going to duplicate...

  • By
    CSS Sprites

    The idea of CSS sprites is pretty genius. For those of you who don't know the idea of a sprite, a sprite is basically multiple graphics compiled into one image. The advantages of using sprites are: Fewer images for the browser to download, which means...


  1. Aicke Schulz

    I want to mention, that there are already two similar solutions for MooTools, realized as “pseudo events”:

  2. Rolf

    Yes yes, exactly why I ripped that method out of _.js code and put it inside my Moo code for window resize events :) – good tip to share!

  3. piotr

    In case you are already using Mootools in the project, consider Events.Pseudos :once, :throttle and :pause (

    window.addEvent('resize:throttle(400)', function(){
        // Will only fire once every 400 ms
  4. Alex

    You always post things just in time. THANKS!

  5. good one! i think it’s the same with Ben Alman’s debounce which is a jQuery plugin

  6. This is really useful. very snap and play which I like. I’m interested to see if this will work on a mobile device and what listeners other listeners I could use. Thanks for the post.

  7. Thanks, really interesting.

  8. Albert

    Great, just what I needed. Can’t use MooTools event.pseudos because I’m bounded to version 1.2.5

  9. Alfonso Perez

    This is the nth-time I benefit from one of your posts, so I have decided to take some seconds to say: thanks!,

    btw, as my humble way of saying thanks, I have paused for a moment adblock and show some genuine interest for your sidebar ad ;-).

  10. Volkan

    Why they used the code like that?

    func.apply(context, args);

    I can change it with func() and it executes as is.

  11. Guy

    I know this is an old post but it’s still coming up as the second hit for the google search ‘underscore debounce’ so I thought I’d chip in.

    The function you’re describing in the 2nd paragraph – “…we can ensure it fires only every n milliseconds during the resize..” seems to actually be _throttle.
    _debounce only calls the given function once, an amount of time only after it has stopped being continually fired.


  12. Dick

    Damn confusing code, your documentation skills and variable naming needs improving. There’s simpler code to do this on the net too.

    • NotHim

      @Dick As stated in the article itself, this code is part of the Underscore.js library, not his code. If you have issues with the documentation and variable naming, bring it up to the Underscore.js developers.

  13. S

    So immediate only applies to the first click? I was assuming that it made all clicks immediate, so i was really confused why the timeout variable was being compared in callnow.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!