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.syncto use a different persistence strategy, such as WebSockets, XML transport, or Local Storage. - Override
Backbone.ajaxif you want to use a custom AJAX function, or your endpoint doesn’t support thejQuery.ajaxAPI.
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); });