Software, life, and random thoughts
Home/Categories/Javascript/Backbone.js Poller/

Backbone.js Poller

Lets say you have a Backbone.js based messaging system on your application, and you want to stay synced with the server so you could alert your users when a new message arrives. You would like to call the server once every couple of seconds and ask for status updates. Or maybe your model represents an on going background task, you want to poll for status updates. You could start with something basic such as:

function poll(collection, delay) {
  setInterval(function () {
    collection.fetch({ data: { foo: 'bar' } })
  }, delay)
}

This works, but has some flaws:

  1. You may end up running simultaneous requests hitting the browser’s allowed connection per host limit (typically 6, 2 on IE7, according to browserscope)
  2. Nothing prevents you from running the function multiple time with the same collection
  3. You can’t easily stop the process, and abort running requests
  4. It doesn’t handle cases where we want to stop polling a model on a condition (say, when it’s task is done)

This may results in unnecessary load on the server side

You could run the next request only upon successful fetch request, and write something like this:

function poll(collection, delay) {
  collection.fetch({
    data: { foo: 'bar' },
    success: function () {
      setTimeout(function () {
        poll(collection, delay)
      }, delay)
    }
  })
}

This solves the first problem bit doesn’t help other issues. It takes a little more than that, and starts smelling like a special helper is needed. You could add a poll() and unpoll() methods to your base models or collections using inheritance or mixin. I wouldn’t like to promote such approach since it breaks the model’s interface and introduces tight coupling between the model and application state. This easily becomes a slippery way down to maintenance hell. A better pattern would be to use an external helper that will keep our interfaces clean and our models stateless and decoupled.

I ended up writing a Backbone Poller, A polling helper utility for Backbone.js. a basic usage for our messaging system will could like

var inbox = new InboxCollection()
var poller = Backbone.Poller.get(inbox, {
  delay: 2000,
  data: { sort: 'date desc' }
})
poller.on('success', function () {
  // do something on every successful fetch
})
poller.start()

A more advanced usage for our long going offline task could look like

var options = {
  delay: 2000,
  // when this becomes false the poller will stop
  condition: function (model) {
    return model.get('done') !== true
  }
}
var task = new OfflineTaskModel()
var poller = Backbone.Poller.get(task, options)
poller.on('complete', function () {
  // task is done, do something
})
task.set('command', 'some-long-procedure')
task.save(
  {},
  {
    success: function () {
      poller.start()
    }
  }
)

The code and examples are available under the MIT license in github.

©2023 Uzi Kilon