Chaining jquery.Deferred
Hacking jquey.Deferred so that we can chain deferred methods 'prettily'... (see http://forum.jquery.com/topic/a-case-for-deferred-chain)
by Plippie Plop
JavaScript
//Example: We want to construct a message "ABC" from three asynchronous messages ("A", "B", "C")
//this is required for Chrome (I gave up on IE9 - usability disaster)
function log(m) { console.log.apply(console, [m]); };
var asyncMessage; //declare before defining, as we will be redefining afterwards.
asyncMessage = function(msg) {
var dfd = new $.Deferred();
setTimeout(function() { dfd.resolve(msg); }, 1000);
return dfd.promise();
};
//Naive attempt at using 'done'
asyncMessage("Naive: A")
.done(function(m) { return asyncMessage(m + "B"); })
.done(function(m) { return asyncMessage(m + "C"); })
.done(log); // -> outputs "Naive: A"
//The problem is that "done" doesn't return a new Deferred, but returns the previous one... so the "A" message just 'drops through'
//What you actually need, to get it working (yucky yuck)
asyncMessage("Ugly: A")
.done(function(m) { return asyncMessage(m + "B").done(
function(m) { return asyncMessage(m + "C").done(log); });
});
//Aim: add a .chain() function to jquery.Deferred, so that we can chain several dependent asynchronous functions together, with each one being called with the results of the preceding one.
//As far as I can see, there's no way to inject the chain method on to Deferred, but we *can* inject our own object into the promise() function. So here we create a function which will generate a chainable promise for us...
var Chainable = function Chainable() {
return {
chain : function(next) { //next is another function which returns Deferred
var newDef = $.Deferred(); //we will resolve this when next is done
//next line: call next with a||null for method-tolerance
this.done(function(a) { next(a||null).done(newDef.resolve); });
return newDef.promise(Chainable());
}
};
}
//AFTER
//Redefine asyncMessage, the only difference is in the last...