Skip to content

Instantly share code, notes, and snippets.

@micho
Created December 5, 2010 00:40
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save micho/728639 to your computer and use it in GitHub Desktop.
Save micho/728639 to your computer and use it in GitHub Desktop.
Throttle and debounce examples
// Run the function as soon as it's called, but prevent further calls during `delay` ms
// Example: function.throttle(200) will only run function() once every 200 ms.
// Useful, for example, to avoid constant processing while typing in a live search box.
Function.prototype.throttle = function(delay) {
var fn = this
return function() {
var now = (new Date).getTime()
if (!fn.lastExecuted || fn.lastExecuted + delay < now) {
fn.lastExecuted = now
fn.apply(fn, arguments)
}
}
}
// Instead of calling the function immediately, wait at least `delay` ms before calling it.
// Example: function.debounce(200) will only call the function after a 200ms pause.
// Useful, for example, to check an available username (wait to pause typing and check).
Function.prototype.debounce = function(delay) {
var fn = this
return function() {
fn.args = arguments
fn.timeout_id && clearTimeout(fn.timeout_id)
fn.timeout_id = setTimeout(function() { return fn.apply(fn, fn.args) }, delay)
}
}
setTimeout( function() {
times_called_yell = 0
yell = function() { times_called_yell++ }.throttle(200)
setTimeout(yell, 0) // will fire
setTimeout(yell, 100)
setTimeout(yell, 250) // will fire
setTimeout(yell, 300)
setTimeout(yell, 350)
setTimeout(yell, 500) // will fire
setTimeout(function() { console.log(times_called_yell == 3 ? "[OK] Throttle is executed correctly" : "[FAILED] Throttle found args "+times_called_yell) }, 1000)
times_called_sing = 0
sing = function() { times_called_sing++ }.debounce(100)
setTimeout(sing, 50)
setTimeout(sing, 120)
setTimeout(sing, 200) // will fire
setTimeout(sing, 400)
setTimeout(sing, 450) // will fire
setTimeout(function() { console.log(times_called_sing == 2 ? "[OK] Debounce is executed correctly" : "[FAILED] Debounce found args: "+times_called_sing) }, 1000)
f = function(a,b,c) {
console.log((a+b+c) == 66 ? "[OK] Throttle accepts args" : "[FAILED] Throttle failed with args: "+a+" "+b+" "+c)
}.throttle(100)
f(11,22,33)
g = function(a,b,c) {
console.log((a+b+c) == 66 ? "[OK] Debounce accepts args" : "[FAILED] Debounce failed with args: "+a+" "+b+" "+c)
}.debounce(100)
g(11,22,33)
context_object = new Object
context_object.some = "property"
context_throttle_test = function() {
console.log( this.some == "property" ? "[OK] Throttle sets `this` context" : "[FAILED] Throttle context: "+this)
}.bind(context_object).throttle(100)
context_throttle_test()
context_debounce_test = function() {
console.log( this.some == "property" ? "[OK] Debounce sets `this` context" : "[FAILED] Debounce context: "+this)
}.bind(context_object).debounce(100)
context_debounce_test()
}, 1000)
@KATT
Copy link

KATT commented Feb 6, 2014

came here off google, just wanted a quick throttle implementation.

your Function.prototype.throttle won't fire if it's only called once since it last got fired, you need to use a timer.

Rewrote it, it has a slight different approach and delays all calls with delay ms. Could be combined with your lastExecuted-logic to also be called immediately on first call.

function throttle(fn, delay) {
  var timeout;
  return function() {
    var args = arguments;
    var context = this;
    if (!timeout) {
      timeout = setTimeout(function() {
        timeout = 0;
        return fn.apply(context, args)
      }, delay);
    }
  };
}

// (optional) if you want to add the fn to the `Function`'s prototype
Function.prototype.throttle = function(delay) {
  return throttle(this, delay);
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment