-- EDIT --
I encountered a weird thing recently about promises, but I guess it's maybe because it's against the philosophy of promises.
Considering the following code :
// Assuming Auth is just a simple lib doing http requests with promises
Auth.signup()
.then(succCall, errCall)
.then(loginSucc, loginErr)
// My callbacks here
function succCall (){
// OK, send second promise
console.log('succCall');
return Auth.login();
}
function errCall(){
// I do some things here and now
// I want to break out from here
console.log('errCall');
}
function loginSucc(){
// This is the callback of the login method when it went OK
// I want to enter here ONLY if with go through the succCall
console.log('loginSucc');
}
function loginErr(){
// This is the callback of the login method when it went not ok
// I want to enter here ONLY if with go through the succCall
console.log('loginErr');
}
Here if something goes wrong in Auth.signup(), this is what show :
- errCall, loginSucc
if i do a $q.reject() in the errCall this is what happens :
- errCall, loginErr
and this is what i want :
- errCall... finish, stop here
Now, the problem is, it goes in errCall when signup goes wrong, that's good, but then it enters loginSucc...
I want to break out of the then chain when any errorCallback (which is errCall or loginErr here) is encountered.
-- EDIT --
I think i was misunderstood by some mean, i want to totally break the chain without check in any other "then" if something went wrong.
As if i was saying : if first then is wrong stop here, if first then ok continue, if second "then" ok continue, if third "then" wrong, stop
// Just like if i did the following but by chainning "then" methods
// My callbacks here
function succCall (){
// OK, send second promise
return Auth.login().then(loginSucc, loginErr);
}
My point is, i don't want only one error handler if i have many "then" chained
-- EDIT --
I encountered a weird thing recently about promises, but I guess it's maybe because it's against the philosophy of promises.
Considering the following code :
// Assuming Auth is just a simple lib doing http requests with promises
Auth.signup()
.then(succCall, errCall)
.then(loginSucc, loginErr)
// My callbacks here
function succCall (){
// OK, send second promise
console.log('succCall');
return Auth.login();
}
function errCall(){
// I do some things here and now
// I want to break out from here
console.log('errCall');
}
function loginSucc(){
// This is the callback of the login method when it went OK
// I want to enter here ONLY if with go through the succCall
console.log('loginSucc');
}
function loginErr(){
// This is the callback of the login method when it went not ok
// I want to enter here ONLY if with go through the succCall
console.log('loginErr');
}
Here if something goes wrong in Auth.signup(), this is what show :
- errCall, loginSucc
if i do a $q.reject() in the errCall this is what happens :
- errCall, loginErr
and this is what i want :
- errCall... finish, stop here
Now, the problem is, it goes in errCall when signup goes wrong, that's good, but then it enters loginSucc...
I want to break out of the then chain when any errorCallback (which is errCall or loginErr here) is encountered.
-- EDIT --
I think i was misunderstood by some mean, i want to totally break the chain without check in any other "then" if something went wrong.
As if i was saying : if first then is wrong stop here, if first then ok continue, if second "then" ok continue, if third "then" wrong, stop
// Just like if i did the following but by chainning "then" methods
// My callbacks here
function succCall (){
// OK, send second promise
return Auth.login().then(loginSucc, loginErr);
}
My point is, i don't want only one error handler if i have many "then" chained
Share Improve this question edited Dec 21, 2015 at 17:58 darkylmnx asked Dec 21, 2015 at 15:38 darkylmnxdarkylmnx 2,0915 gold badges24 silver badges39 bronze badges 8-
I think to break the chain you have to
reject
the promise inside theerrCall
function. – koox00 Commented Dec 21, 2015 at 15:47 - @koox00 nope a reject just enters the next error, so loginErr here, and this is what i don't want – darkylmnx Commented Dec 21, 2015 at 16:29
-
@SoluableNonagon has the right answer - use
catch
and skip yourerrCall
andloginErr
functions, and place their logic within thecatch
. You'll have to look at the error that thecatch
callback caught but it is the one way to acplish what you want. – Adam Jenkins Commented Dec 21, 2015 at 17:01 - the question was not to find an alternative, because what you are telling here is an alternative, this is not something that break's out from the chain. I know this method but it's not the one i want, but thanks anyway – darkylmnx Commented Dec 21, 2015 at 17:05
-
can you try to break it down in 2 parts?
Auth.signup() .then(succCall, errCall)
,succCall.then(loginSucc, loginErr)
, something like that – koox00 Commented Dec 21, 2015 at 17:37
4 Answers
Reset to default 2What is effectively happening is this:
try {
try {
var a = succCall();
} catch(e1) {
a = errCall(e1);
}
var b = loginSucc(a);
} catch(e2) {
b = loginErr(e2);
}
You can break out of the chain by calling
return $q.reject('Reason Err was called');
in your errCall()
function.
EDIT:
As OP remarked by calling $q.reject
the code will enter the loginErr
function.
Alternatively you can modify your code like this:
Auth.signup()
.then(function(a) {
succCall()
return loginSucc(a).then(null, loginErr);
}, errCall)
You can read more in these two SO question:
- Break promise chain
- Break Out of then promises in Angularjs
This also is a helpful read : Flattening Promise Chains
errCall
function needs tor return a promise, and that promise needs to be rejected for loginErr to be fired.
function errCall(){
// i do some things here and now
return $q(function(resolve, reject) {
// auto reject
reject();
});
}
Alternatively try .catch
:
Auth.signup()
.then(succCall)
.then(loginSucc)
.catch(function(err){
// caught error, problem is you won't know which function errored out, so you'll need to look at the error response
});
Just don't pass any errCall
or loginErr
to then
and use catch()
in the end of the promise chain and it will be interrupted on first error, which will be passed to catch()
. If you want explicitly process error of Auth.signup()
then your errCall
should look like this:
function (err) {
if(isFatal(err)) {
return Promise.reject(new Error('Fatal!')); //`catch()` handler will be called with `new Error('Fatal!')`
} else {
return 'something'; //next `then()` handler will be called with 'something'
}
}
Your best option is to return a promise that is never resolved from errCall()
:
function errCall() {
console.log('errCall');
return $q.defer().promise;
}
But you are right, what you are trying to do is "against the philosophy of promises".
Why you shouldn't do it
It is of course a problem that your loginSucc
function is called when an error occurs during evaluation of the first promise. However, that can be fixed by rejecting once again in errCall
as others have already pointed out. But you should not try to avoid the execution of loginErr
, otherwise something is conceptually wrong with your code.
The evaluation of the expression
Auth.signup().then(succCall, errCall)
yields another promise. The contract is that a promise has a then()
method taking two callbacks as parameters, one for success and one for failure. The contract is also that the success callback is called when the promise is evaluated successfully and that the error/failure callback is called in all other cases. If you intend to never call either of those, don't use a promise!