Ultimate Debouncer

by Scott Kaye

JavaScript

// Returns functions that will only success if time has passed since the previous call
/*
	Usage:
		var d = new Debouncer();
		var func = function() { console.log("Hello, world!"); }

		:: debounced ::
			var debounced = d.debounced(func, 200);

			debounced();  // Hello, world! after 200ms
			debounced();  // Does nothing
			debounced();  // Does nothing

			setTimeout(debounced, 1000); // Prints Hello, world! after 1 second

		:: throttled ::
			var debounced = d.throttled(func, 200);

			debounced();  // Hello, world! immediately
			debounced();  // Does nothing
			debounced();  // Does nothing

			setTimeout(debounced, 1000); // Prints Hello, world! after 1 second
*/
function Debouncer() {
    var count = 0;
    var timers = {};

    // Returns a function that will only if a certain period of time has passed since the previous successful call
    // Good for functions that run after a user is finished an interaction
    // Benefits from a low delay time (100ms)
    this.debounced = function(fn, delay) {
        var timeoutId;

        return function() {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(fn.bind(this), delay);
        };
    };

    // Returns a function that will run only if a certain period of time has passed since the previous valid call
    // Good for functions that can run while the user is interacting
    // Benefits from a high delay time (500ms)
    this.throttled = function(fn, delay) {
        var id = ++count;

        return function() {
            var now = Date.now();

            if ((timers[id] || 0) < now - delay) {
                timers[id] = now;
                fn.call(this);
            }
        };
    };
}