When to Use deferred.reject()?

2019-08-12 16:54发布

问题:

I’m very confused about when to use deferred.resolve() and deferred.reject().

Quick Example

var doSomething = function() {

    var deferred = $.Deferred();

    if ( typeof myVar === "object" ) {

        // Do something with myVar - Start.

            deferred.resolve();

        // Do something with myVar - End.

    } else {

        // myVar isn't an object, but the function has finished executing
        // and that's what I want to know.
        // With reject() I'll be forced to use always() instead of done()
        // because there'll be also a fail() method available if myVar
        // is not an object.
        deferred.reject();
    }

    return deferred.promise();
};

Question

Any tips or rules about when I should use deferred.reject()?

NOTE

myVar is animated at some point. After animation completes, I do some other things and only then I resolve the Deferred object.

回答1:

.resolve() and .reject() are two different possible branches of outcomes from your promise.

Though, its really up to the programmer how to best use those two possible paths, .resolve(data) is typically used for a successful outcome and optionally returning data with the successful outcome and .reject(err) is typically used for an error condition and returning some info about the error.

Which you use determines which callbacks are triggered on .then(f1, f2) for this promise. If you use .resolve(), then f1 is called (assumed to be a success handler callback). If you use .reject(), then f2 is called (assumed to be an error handler callback).


There are also some higher level functions that operate on promises such as $.when() (in the jQuery world) that assume .resolve() is success and .reject() is an error condition. $.when() calls it's callback when all promises have resolved or when any promise is rejected (assumed to be an error condition).


If the calling code only really cares when the operation is completed (whether it finished successfully or not), then you have three different options and which to choose is really your choice:

1) You can use .resolve() and .reject() and then put your completion handler in a function and call it like this:

doSomething.then(doneHandler, doneHandler);

2) You can use .resolve() and .reject() and then use .always() like this:

doSomething.always(...);  

A disadvantage of .always() is that it's a jQuery specific method, and not a promise standard so it may change in the future. For example, the Bluebird and Q promise libraries use .finally() for this type of feature.

3) You can just use .resolve() for both paths so you only have one completion handler regardless of how/why it finished.

doSomething.then(fn);

The advantage of the first two options is that sometime in the future, the caller can more easily implement different behavior for a successful completion vs. an error completion.

The advantage of the third option is that you can more easily use this promise with something like $.when() to know when it and some other things are all done.


In looking at your specific code, you should keep in mind that promises are best used when you have asynchronous operations (such as ajax calls). If you don't have any asynchronous operations, then you may as well just directly return a value from your function to indicate success or failure and let the calling code check that error and branch based on that. Using promises is not as simple as plain procedural code for synchronous activities (such as the example code in your question) so there is usually no good reason to use promises for purely synchronous coding.