Skip to content

Commit

Permalink
Backbone.Promise
Browse files Browse the repository at this point in the history
Competes with jashkenas#2489.

Specifically, is implements `Backbone.Promise` instead of
`Backbone.Deferred`, so it can be easily swapped with any ES6
compatible Promise library.
  • Loading branch information
jridgewell committed May 31, 2015
1 parent 6518a4c commit 69b74cf
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 10 deletions.
34 changes: 29 additions & 5 deletions backbone.js
Original file line number Diff line number Diff line change
Expand Up @@ -601,9 +601,9 @@
// `set(attr).save(null, opts)` with validation. Otherwise, check if
// the model will be valid when the attributes, if any, are set.
if (attrs && !wait) {
if (!this.set(attrs, options)) return false;
if (!this.set(attrs, options)) return Backbone.Promise.reject(this.validationError);
} else {
if (!this._validate(attrs, options)) return false;
if (!this._validate(attrs, options)) return Backbone.Promise.reject(this.validationError);
}

// After a successful server-side save, the client is (optionally)
Expand Down Expand Up @@ -639,7 +639,7 @@
// Optimistically removes the model from its collection, if it has one.
// If `wait: true` is passed, waits for the server to respond before removal.
destroy: function(options) {
options = options ? _.clone(options) : {};
options = _.extend({}, options);
var model = this;
var success = options.success;
var wait = options.wait;
Expand All @@ -655,9 +655,9 @@
if (!model.isNew()) model.trigger('sync', model, resp, options);
};

var xhr = false;
var xhr;
if (this.isNew()) {
_.defer(options.success);
xhr = Backbone.Promise.resolve().then(options.success);
} else {
wrapError(this, options);
xhr = this.sync('delete', this, options);
Expand Down Expand Up @@ -1408,6 +1408,30 @@
return Backbone.$.ajax.apply(Backbone.$, arguments);
};

// A psuedo Promise implementation used to ensure asynchronous methods
// return thenables.
// Override this if you'd like to use a different ES6 library.
Backbone.Promise = function() {
throw new Error('Backbone does not provide a spec compliant Promise by default.');
};

// A helper method that forces jQuery's first `then` callback to be
// executed asynchronously.
// This is used so we can guarantee our async return values execute
// callbacks async, not async sometimes and sync other times.
var asyncDeferred = function(method) {
return function(value) {
var deferred = Backbone.$.Deferred();
_.defer(deferred[method], value);
return deferred.promise();
};
};

_.extend(Backbone.Promise, {
resolve: asyncDeferred('resolve'),
reject: asyncDeferred('reject')
});

// Backbone.Router
// ---------------

Expand Down
23 changes: 18 additions & 5 deletions test/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -662,13 +662,19 @@
this.ajaxSettings.success();
});

test("destroy", 3, function() {
asyncTest("destroy", 3, function() {
doc.destroy();
equal(this.syncArgs.method, 'delete');
ok(_.isEqual(this.syncArgs.model, doc));

var newModel = new Backbone.Model;
equal(newModel.destroy(), false);
var promise = newModel.destroy();
var async = false;
promise.then(function() {
ok(async, 'then chains asynchronously');
start();
});
async = true;
});

test("destroy will pass extra options to success callback", 1, function () {
Expand Down Expand Up @@ -1156,11 +1162,18 @@
}});
});

test("#1433 - Save: An invalid model cannot be persisted.", 1, function() {
asyncTest("#1433 - Save: An invalid model cannot be persisted.", 2, function() {
var model = new Backbone.Model;
model.validate = function(){ return 'invalid'; };
model.validate = function(){ return { error: 'invalid' }; };
model.sync = function(){ ok(false); };
strictEqual(model.save(), false);
var promise = model.save();
var async = false;
promise.then(null, function(reason) {
strictEqual(reason, model.validationError, 'passes error to onRejected');
ok(async, 'then chains asynchronously');
start();
})
async = true;
});

test("#1377 - Save without attrs triggers 'error'.", 1, function() {
Expand Down

0 comments on commit 69b74cf

Please sign in to comment.