1

I have a function that submits some data. Depending on the state of some boolean, I might not want to submit this data. However, the caller is always expecting a deferred object as the return value to check .done() or .fail(). It seems you cannot return null or return nothing when something expects done/fail (makes sense), so I don't know how to return from this async call.

I can hack in a $.Deferred object and immediately resolve/return it, but that seems like bad design. I can't change the calling method here.

How can I return a deferred object or some other return value that satisfies .done() or .fail() without using a deferred object?

function foo(a) {
    bar(a).done(function () {
        console.log("done");
    }).fail(function () {
        console.log("fail");
    });
}

function bar(a) {
    if (a){
        // Could create a $.Deferred and resolve it
        return;
    }

    return doAsync();
}

function doAsync() {
    var defer = $.Deferred();
    defer.resolve();
    return defer.promise();
}

foo(false); // fine
foo(true); // error

http://jsfiddle.net/ma4grjj4/2/

BarryBones41
  • 1,361
  • 1
  • 13
  • 30
  • 7
    *"I can hack in a $.Deferred object and immediately resolve/return it, but that seems like bad design."* Not at all. – Felix Kling Sep 09 '15 at 15:13
  • @FelixKling Hmm, really? What I would do ideally is in `foo` skip the entire call of `bar`, but a lot of stuff happens inside of `bar().done` that needs to occur in both cases. – BarryBones41 Sep 09 '15 at 15:31
  • 1
    That's exactly what you get with [immediately resolved promise](http://stackoverflow.com/questions/24794434/immediately-return-a-resolved-promise). It's not an antipattern by any means. – raina77ow Sep 09 '15 at 15:34

1 Answers1

1

The main problem is that it's usually a design smell to have boolean arguments that changes the process flow of a function.

I think you will agree that doing something like the following makes no sense:

function process(doNotProcess) {
    if (doNotProcess) return;

    //process
}

In the above example, it would make more sense to simply not call on process() to avoid processing.

"What I would do ideally is in foo skip the entire call of bar, but a lot of stuff happens inside of bar().done that needs to occur in both cases"

That code should probably be factored out of the done callback and put in a different function, which would allow you to reuse it without having to call bar.

"I can hack in a $.Deferred object and immediately resolve/return it, but that seems like bad design."

Creating deferred objects and resolving them right away is a quite standard approach when you need to standardize the use of an API that may have a synchronous or asynchronous implementation.

It's a very good practice to do so because it frees the client from having to rely on implementation details.

plalx
  • 42,889
  • 6
  • 74
  • 90