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...