简体   繁体   中英

Why are multiple 'fail' handlers being called when several 'then' handlers are chained to a deferred?

My project involves workflows that uses muliple API's that return deferred promises. I am using jQuery 1.8

I understand that the difference between .done() and .then() is that .then() returns a new promise. In my example, I would expect that if the first deferred was rejected, that only the first .fail() handler would be executed because the second is chained to the new promise. In execution, both fail handlers are executed.

var firstDeferred = $.Deferred(), secondDeferred = $.Deferred();

firstDeferred.promise()
.fail(function (error) {
    console.log(error);
})
.then(function () {
    return secondDeferred.promise();
})
.fail(function (error) {
    console.log(error);
});

firstDeferred.reject('first deferred object');
//secondDeferred.reject('second deferred object');

My Expected Result:

> first deferred object

Actual Result:

> first deferred object
> first deferred object

Why are both .fail() handlers being called? How can I structure my workflow in a way that the the handlers are only called when the specific deferred promises are rejected?

You're not chaining anything to the promise you return in the then() callback, because that callback never gets executed.

then() takes these arguments:

then( doneFilter , failFilter )

Your callback is the 1st argument, hence it's the doneFilter . But the first promise fails, so then() doesn't call your callback. It would call the failFilter , but you don't pass anything for that 2nd argument.

Quoting from the docs :

If the filter function used is null, or not specified, the promise will be resolved or rejected with the same values as the original.

And since the failFilter argument isn't given, then() just forwards the state of the first promise, which triggers the 2nd fail() handler.

This works:

var firstDeferred  = $.Deferred(),
    secondDeferred = $.Deferred();

firstDeferred.promise()
.fail(function (error) {
    console.log(error);
})
.then(null, function () { // Notice the null
    return secondDeferred.promise();
})
.fail(function (error) {
    console.log(error);
});

firstDeferred.reject('first deferred object');
secondDeferred.reject('second deferred object');

which logs:

first deferred object
second deferred object 

This happens because then return a new promise (which result is piped to the result of its callback returned promise).

A promise can have two final state: resolved or failed. So, as the first deferred failed, the second can never be resolved, so it fails. If then wasn't bubbling the failing, you'd found yourself with an indefinitely pending promise. This could be a risk for memory leaks.

Just changed the way you manage the then fail function if you only want it to be run if it has actually run.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM