Skip to content

Commit

Permalink
Remove hard dependency on jQuery.Deferred quirks
Browse files Browse the repository at this point in the history
jQuery.Deferred objects are not compliant with the Promises/A+ standard.
Replaces Promise#done() (not part of the standard) with Promises#then()

This fixes the jQuery.Deffered dependency discussed in #980.
It also exposes Marionette.Deferred as a means to configure the desired
implementation.

e.g.
```
Backbone.Marionette.Deferred = Q.defer; // kriskowal/q
Backbone.Marionette.Deferred = when.defer; // cujojs/when
```
  • Loading branch information
cmaher authored and samccone committed Jun 17, 2014
1 parent ab727a8 commit b5cbcb9
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 6 deletions.
37 changes: 37 additions & 0 deletions docs/marionette.configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Marionette Configuration

Marionette has a few globally configurable settings that will
change how the system works. While many of these subjects are covered
in other docs, this configuration doc should provide a list of the
most common items to change.

## Documentation Index

* [Marionette.Deferred](#deferred)

## Marionette.Deferred <a name="deferred"></a>

By default, Marionette makes use of `Backbone.$.Deferred` to create
thenable objects. All that is needed is a Deferred that has the
following properties:

1. `promise`: a Promises/A+ thenable, or a function that returns one
2. `resolve`: a function that resolves the provided promise with a value

For example:

```js
var deferred = Marionette.Deferred();

_.result(deferred, 'promise').then(function (target) {
console.log("Hello, " + target + "!");
});

deferred.resolve("world"); // asynchronous "Hello, world!"
```

If you wish to use a specific promise library, you can override the default via:

```js
Marionette.Deferred = myDeferredLib;
```
27 changes: 27 additions & 0 deletions spec/javascripts/callbacks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,31 @@ describe('callbacks', function() {
expect(this.numCallbacks).to.equal(1);
});
});

describe("when Marionette.Deferred().promise is an object", function(){
beforeEach(function(){
this.sandbox = sinon.sandbox.create();

this.sandbox.stub(Backbone.Marionette, "Deferred", function(){
var deferred = Backbone.$.Deferred();
deferred.promise = deferred.promise();
return deferred;
});

var callbacks = new Backbone.Marionette.Callbacks();

this.spy = sinon.spy();
callbacks.add(this.spy);

callbacks.run();
});

afterEach(function(){
this.sandbox.restore();
});

it("should execute the callbacks", function(){
expect(this.spy).to.have.been.called;
});
});
});
3 changes: 3 additions & 0 deletions src/build/marionette.bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ var Marionette = (function(global, Backbone, _){
var Marionette = {};
Backbone.Marionette = Marionette;

// Get the Deferred creator for later use
Marionette.Deferred = Backbone.$.Deferred;

// @include ../marionette.helpers.js
// @include ../marionette.triggermethod.js
// @include ../marionette.domRefresh.js
Expand Down
3 changes: 3 additions & 0 deletions src/build/marionette.bundled.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@

Backbone.Marionette = Marionette;

// Get the Deferred creator for later use
Marionette.Deferred = Backbone.$.Deferred;

// @include ../marionette.helpers.js
// @include ../marionette.triggermethod.js
// @include ../marionette.domRefresh.js
Expand Down
3 changes: 3 additions & 0 deletions src/build/marionette.core.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
// Get the DOM manipulator for later use
Marionette.$ = Backbone.$;

// Get the Deferred creator for later use
Marionette.Deferred = Backbone.$.Deferred;

// @include ../marionette.helpers.js
// @include ../marionette.triggermethod.js
// @include ../marionette.domRefresh.js
Expand Down
17 changes: 11 additions & 6 deletions src/marionette.callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// and executing them at a later point in time, using jQuery's
// `Deferred` object.
Marionette.Callbacks = function() {
this._deferred = Backbone.$.Deferred();
this._deferred = Marionette.Deferred();
this._callbacks = [];
};

Expand All @@ -15,26 +15,31 @@ _.extend(Marionette.Callbacks.prototype, {
// guaranteed to execute, even if they are added after the
// `run` method is called.
add: function(callback, contextOverride) {
var promise = _.result(this._deferred, 'promise');

this._callbacks.push({cb: callback, ctx: contextOverride});

this._deferred.done(function(context, options) {
if (contextOverride) { context = contextOverride; }
callback.call(context, options);
promise.then(function(args) {
if (contextOverride){ args.context = contextOverride; }
callback.call(args.context, args.options);
});
},

// Run all registered callbacks with the context specified.
// Additional callbacks can be added after this has been run
// and they will still be executed.
run: function(options, context) {
this._deferred.resolve(context, options);
this._deferred.resolve({
options: options,
context: context
});
},

// Resets the list of callbacks to be run, allowing the same list
// to be run multiple times - whenever the `run` method is called.
reset: function() {
var callbacks = this._callbacks;
this._deferred = Backbone.$.Deferred();
this._deferred = Marionette.Deferred();
this._callbacks = [];

_.each(callbacks, function(cb) {
Expand Down

0 comments on commit b5cbcb9

Please sign in to comment.