jashkenas / backbone

Give your JS App some Backbone with Models, Views, Collections, and Events
http://backbonejs.org
MIT License
28.1k stars 5.38k forks source link

How to debounce view events? #315

Closed meleyal closed 13 years ago

meleyal commented 13 years ago

How would you debounce this keyup listener so the subdomain check only happens after a delay?

This kind of works, but the _checkSubdomain function is still called for each keyup event, the calls just get delayed:

events: {
  'keyup #subdomain' : 'checkSubdomain'
},

checkSubdomain: function(e){
  this.debounced = _.debounce(_.bind(this._checkSubdomain, this, e), 2000);
  this.debounced();
},

_checkSubdomain: function(e){
  // called once for each keyup event :(     
  console.log(e.target.value);
}
meleyal commented 13 years ago

I ended up solving it like this:

events: {
  'keyup #subdomain' : 'checkSubdomain'
},

initialize: function(){
  this._getSubdomain = _.debounce(_.bind(this.getSubdomain, this), 2000);    
},

checkSubdomain: function(e){
  var subdomain = e.target.value;    
  this._getSubdomain(subdomain);
},

getSubdomain: function(subdomain){
  // called only once every 2 seconds :)
  console.log(subdomain);
}
joshmosh commented 12 years ago

@meleyal: Thank you for documenting this. I found this very useful on a project I am working on.

kirbysayshi commented 12 years ago

I came across this same issue, and solved it this way:

events: {
  'keyup #subdomain' : 'checkSubdomain'
},

initialize: function(){
  this.getSubdomain = _.debounce(this.getSubdomain, 2000);    
},

checkSubdomain: function(e){
  // called only once every 2 seconds :)
  console.log(subdomain);
}

Because you're defining the events in the events object, the method is already bound to the proper context. Seems to be working fine so far!

jsoncorwin commented 12 years ago

I know this is already closed, but I was looking for a solution and just tested out the following, it's a bit strange, but I suppose no stranger than any previous ones, and seems to work:

events: {
    'keyup #subdomain': 'checkSubdomain'
},

checkSubdomain: _.debounce(function(){
    // do something
}, 2000)
achur commented 12 years ago

@jsoncorwin nothing strange about it:

The problem with the original code by @meleyal was that _.bind returns a new debounced function each time, so though it was technically debounced, a new one was created/called on each keyup (defeating the point of debouncing; each call is merely delayed -- since it is only called once, it waits and is never called again so it executes). The right solution is to call debounce once, then to use the return value every time (which you accomplish by calling debounce at model-definition time).

Hopefully this brings some clarity as to why this was happening/why these solutions work.

mohandere commented 8 years ago

Either you can write also,

events: {
   'keyup #subdomain': _.debounce(function(){
      this. getSubdomain();
   }, 500),
},
linus-amg commented 8 years ago

you should always create the debounced (edit: bound, throttled, memoized) version of a function in the initialize method (if not earlier) when the 'delay' is not dynamic.

valecarlos commented 7 years ago

it's been a while now, but is @jsoncorwin 's approach the best yet?