I'm trying to figure out a good way to say "Do all of these things, but bail in the case that any of them fails"
What I have right now:
var defer = $q.defer();
this
.load( thingy ) // returns a promise
.then( this.doSomethingA.bind( this ) )
.then( this.doSomethingB.bind( this ) )
.then( this.doSomethingC.bind( this ) )
.then( this.doSomethingD.bind( this ) )
.then( function(){
defer.resolve( this );
} );
;
return defer.promise;
What I ultimately want is to somehow catch any error on that chain so I can pass it on to the defer
promise above. I don't particularly care if the syntax is kept similar to what I have above.
Or even if anyone can just tell me how to stop the above chain.
I'm trying to figure out a good way to say "Do all of these things, but bail in the case that any of them fails"
What I have right now:
var defer = $q.defer();
this
.load( thingy ) // returns a promise
.then( this.doSomethingA.bind( this ) )
.then( this.doSomethingB.bind( this ) )
.then( this.doSomethingC.bind( this ) )
.then( this.doSomethingD.bind( this ) )
.then( function(){
defer.resolve( this );
} );
;
return defer.promise;
What I ultimately want is to somehow catch any error on that chain so I can pass it on to the defer
promise above. I don't particularly care if the syntax is kept similar to what I have above.
Or even if anyone can just tell me how to stop the above chain.
Share Improve this question asked May 30, 2013 at 23:17 user578895user578895 3 |6 Answers
Reset to default 7You can stop angularjs chain by returning rejected promise inside any then callback.
load()
.then(doA)
.then(doB)
.then(doC)
.then(doD);
where doA, doB, doC, doD can have logic like this:
var doA = function() {
if(shouldFail) {
return $q.reject();
}
}
I just stumbled across this and realized all these answers are terribly outdated. Here is the proper way to handle this for anyone that happens to find this post.
// Older code
return this.load(thing)
.then(this.doA, $q.reject)
.then(this.doB, $q.reject)
.then(this.doC, $q.reject)
.then(this.doD, $q.reject)
.then(null, $q.reject);
// Updated code
// Returns the final promise with the success handlers and a unified error handler
return this.load(thing)
.then(this.doA)
.then(this.doB)
.then(this.doC)
.then(this.doD)
.catch(this.handleErrors); // Alternatively, this can be left off if you just need to reject the promise since the promise is already rejected.
// `.catch` is an alias for `.then(null, this.handleErrors);`
You should be able to do that same thing by:
var defer = $q.defer();
this
.load( thingy ) // returns a promise
.then( this.doSomethingA.bind( this ), $q.reject )
.then( this.doSomethingB.bind( this ), $q.reject )
.then( this.doSomethingC.bind( this ), $q.reject )
.then( this.doSomethingD.bind( this ), $q.reject )
.then( defer.resolve.bind( defer, this ), defer.reject.bind( defer ) );
;
return defer.promise;
The best way to handle this and also to catch the problem is the .catch block. Inside any .then block that you wanna kill the promise chain, yes use:
return $q.reject();
However extend it like so...
return $q.reject(new Error('Error Message Here'));
Now in the catch method you will have this
.catch(function(err) {
console.log(err); //This will log the above 'Error Message Here'
});
Now we throw and handle the promise error correctly in the fashion promise failures were meant to be handled.
Okay, this works but I don't like it... Awaiting something better :)
It just seems dirty to create a promise for the sole sake of immediately rejecting it
myApp
.factory( 'chainReject', [ '$q', function( $q ){
return function( err ){
var defer = $q.defer();
defer.reject( err );
return defer.promise;
}
} ] );
...
var defer = $q.defer();
this
.load( thingy ) // returns a promise
.then( this.doSomethingA.bind( this ), chainReject )
.then( this.doSomethingB.bind( this ), chainReject )
.then( this.doSomethingC.bind( this ), chainReject )
.then( this.doSomethingD.bind( this ), chainReject )
.then( defer.resolve.bind( defer, this ), defer.reject.bind( defer ) );
;
return defer.promise;
Looks like this use case has been anticipated and addressed with the use of $q.reject(reason)
defer
, justreturn
thethis.load(…).then(A).then(B).then(C).then(D);
chain! – Bergi Commented Jul 1, 2015 at 17:58