In this blog post I will explain how Backbone.js models can be extended to return an A+ Promise, rather than jQuery’s jqXHR object.
Backbone.js is a JavaScript framework providing models, collections and views to your client-side application.
Bluebird is a full featured Promise/A+ implementation with exceptionally good performance for JavaScript.
Background
In Backbone, a Model is used to:
- Orchestrate data and business logic.
- Load and save from the server.
- Emit events when data changes.
Backbone uses a function called Backbone.sync
every time it attempts to read or save a model to the server. For example, this function is used every time you invoke .save()
and .destroy()
on a model. By default, it uses Backbone.ajax
to make a RESTful JSON request and returns a jqXHR object from jQuery.
As of jQuery 1.5 the jqXHR object implements a Promise interface, giving them all the properties, methods, and behaviours of a Promise (see Deferred object).
A+ Promise instead of jqXHR
When working with Promises, I prefer to use Bluebird - which implements the A+ Promise Standard. For example, rather than using jQuery’s .done
, .fail
and .always
I prefer to use .then
, .catch
and .finally
from Bluebird. This helps ensure all my asynchronous code is inline with the A+ specification.
import { Model } from 'backbone';
let User = Model.extend({ urlRoot : '/users' });
let user = new Book({ id: 1234 });
user.save()
.then(function (res) { console.log('success'); } )
.catch(function (err) { console.log('error', err); });
With Backbone you can override the default behaviour for both Backbone.sync
and Backbone.ajax
.
- Override
Backbone.sync
to use a different persistence strategy, such as WebSockets, XML transport, or Local Storage. - Override
Backbone.ajax
if you want to use a custom AJAX function, or your endpoint doesn’t support thejQuery.ajax
API.
Because we still want to use AJAX, in this example, we will override Backbone.ajax
. This is the default implementation:
Backbone.ajax = function() {
return Backbone.$.ajax.apply(Backbone.$, arguments);
};
We can use Bluebird’s Promise.resolve
function to convert jQuery’s jqXHR
object to an A+ Promise.
import Backbone from 'backbone';
import Promise from 'bluebird';
Backbone.ajax = function() {
let xhr = Backbone.$.ajax.apply(Backbone.$, arguments);
return Promise.resolve(xhr);
};
Collections too
This also works for .fetch
on a Backbone Collection.
import { Collection } from 'backbone';
let Notes = Collection.extend({ url: '/notes' });
let notes = new Notes();
notes.fetch()
.then(function (res) { console.log('success'); } )
.catch(function (err) { console.log('error', err); });