Deferred and Promise chaining tests

Testing then- and addCallback-chaining on deferreds and promises in Dojo 1.5.

HTML

<button onclick="cbseq();">sequential def.addCallBack()s</button>
<button onclick="cbchain();">chained def.addCallBack()s</button>
<br/>
<button onclick="tseq();">sequential def.then()s (with Deferreds)</button>
<button onclick="tchain();">chained def.then()s (with Deferreds)</button>
<br/>
<button onclick="tseq(true);">sequential def.then()s (with promises)</button>
<button onclick="tchain(true);">chained def.then()s (with promises)</button>
<div id="output"></div>

JavaScript

function appendOutput(data) {
    dojo.place('<p>' + data + '</p>', 'output');
}

var r = 0;

function doXHR() {
    //returns a dojo.Deferred (from a dojo.xhr call)
    var def = dojo.xhrPost({
        url: '/echo/html/',
        content: {
            delay: 1,
            html: ++r
        }
    });
    return def;
}

function doXHRPromise() {
    //dojo.xhr* return a full-blown Deferred object even in 1.5
    //(since if they didn't, addCallback/Errback would stop working,
    //which would be a back-compat nightmare).
    //let's return just the promise though, to test what happens when we
    //return a promise (vs. a Deferred) through then's resolveHandler.
    
    //Answer: the same thing happens, because the then function is shared
    //between the Deferred and the promise, and internally when it checks
    //if the resolveHandler returned a promise, it duck-types
    //by looking for the existence of then itself - therefore both work.
    
    return doXHR().promise;
}

function tseq(/*Boolean?*/ promise) {
    //testing a sequence of then calls on a Deferred or promise.
    //this does NOT piggyback; all of them happen at once.
    //This is what dmachi was pointing out as having changed between
    //Deferred and promise.
    
    var
        xhr = (promise ? doXHRPromise : doXHR),
        def = xhr();
    
    def.then(appendOutput);
    def.then(xhr);
    def.then(appendOutput);
    def.then(xhr);
    def.then(appendOutput);
}

function cbseq() {
    //testing a sequence of addCallback calls on a Deferred.
    //unlike with then, this actually does piggyback.
    
    var def = doXHR();
    
    def.addCallback(appendOutput);
    def.addCallback(doXHR);
    def.addCallback(appendOutput);
    def.addCallback(doXHR);
    def.addCallback(appendOutput);
}

function tchain(/*Boolean?*/ promise) {
    //testing a chain of then calls on a Deferred or promise.
    //this piggybacks deferreds.
    var
        xhr = (promise ? doXHRPromise : doXHR),
       ...