Return Fulfilled or Rejected Promise

Today I ran into a situation where one of my functions was part of a chain of promises and I had a condition where if something was true, I didn’t want to fetch some data asynchronously, but if it was false I did want to fetch the data. My initial code looked similar to this:

var i = 0;

function getDataAsync() {
    var def = Q.defer(),
        j = ++i;

    console.log('fetching ' + j);
    setTimeout(function () {
        console.log('done ' + j);
        def.resolve();
    }, 1000);

    return def.promise;
}
 
function doSomething(willGetData) {
    if (willGetData) {
        return;
    }
    return getDataAsync()
        .then(getDataAsync)
        .then(getDataAsync);
}
 
function doSomethingMore(willGetData) {
    console.log('start');
    doSomething(willGetData)
        .then(function () {
            console.log('finish');
        });
}
 
doSomethingMore(true); //Cannot read property 'then' of undefined

You’ll notice the problem lies in doSomething where I am simply returning undefined. The error occurs in doMore because then is not a property of undefined. I needed to return a fulfilled promise to keep the chain unbroken. My initial solution looked something like the code below, but it just felt awkward, like there was too much going on. Too much extra code and…yuck.

function doSomething(willGetData) {
    var def = Q.defer();

    if (willGetData) {
        def.resolve();
        return def.promise;
    }
    
    getDataAsync()
        .then(getDataAsync)
        .then(getDataAsync)
        .then(def.resolve, def.reject);

    return def.promise;
}

So I read through the Q documentation and found a more elegant solution.

function doSomething(willGetData) {
    if (willGetData) {
        return Q();
    }
    return getDataAsync()
        .then(getDataAsync)
        .then(getDataAsync);
}

Calling Q(value) where value isn’t a promise returns a fulfilled promise with value. Conversely, if you needed to return a rejected promise with a value you could use Q.reject(value).

As a fun side note, I also toyed with this hack, which I don’t recommend:

function getThenable() {
    return {
        then: function (func) {
            func();
            return getThenable();
        }
    };
}

It could be used in place of Q() because it returns a ‘thenable’ object.

JSFiddle anyone?

Comments, questions and feedback welcome.