Q: Promise Chaining and Rejection: Doesn't reject kill the chain? - javascript

I have the following chained functions that all implement promises utilizing Q:
validateToken(context).then(parseFormData, get403).then(createReport, get400).then(send200, get400).catch(get500);
e.g. All of them have somewhere within them:
let deferred = q.defer();
..
deferred.resolve(true);
deferred.reject(false);
return deferred.promise;
The first function validateToken calls a deferred.reject. This then results with get403 being called, as expected; but createReport, get400 and get500 are also being called? This confuses me. I thought only the first error handler was hit in the chain?
Can someone please explain what is happening, and if there is a way for me to get the desired behavior where only the most immediate reject/error handler is called?

That depends on what on403 returns. If nothing, it is assumed to be a resolve - which explains the behavior you are seeing. Remember, onReject is equivalent to a catch, which, as a concept, allows you to continue processing as if an error didn't happen
If you want to continue down the reject chain then you have to return Promise.reject(). Otherwise you have to rethink your promise chaining.

Related

Race condition issues with async functions Javascript [duplicate]

I would like to get a deeper understanding of how Promises work internally.
Therefore I have some sample code:
var p1 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
var p2 = new Promise(
function(resolve, reject) {
window.setTimeout(
function() {
resolve('res called')
}, 2000);
});
function chainPromises() {
return p1.then(function(val) {
console.log("p1");
return p2.then(function(val) {
console.log("p2");
return val;
});
});
}
chainPromises().then(function(val) {
console.log(val);
});
Here a link to execute this code.
As you would predict, first p1 is resolved, afterwards p2 and in the end the final then prints the resolv value.
But the API ref states the following:
"then" returns a new promise equivalent to the value you return from
onFulfilled/onRejected after being passed through Promise.resolve
So it would be interesting to know WHEN exactly the "then" function is executed?
Because the final "then" in the code is chained to the chainPromises(), I first thought that
it would execute after the function chainPromises() returns something (in this case another promise).
If this would have been the case the "val" of the final "then" function would be the returned promise.
But instead, the final "then" waits until all promises inside the first "then" which are returned have been resolved.
This absolutely makes sense because in this way, the "then" functions can be stacked, but
I do not really get how this is done, since the API spec. does not really cover what "then" returns and when the "then" functions is executed.
Or in other words, why does the final "then" function wait until all the Promises are resolved inside the chainPromises() function instead of just waiting for the first returned object as the API doc says.
I hope I could make clear what I mean.. :)
About Promise resolution
The thing you're witnessing here is called recursive thenable resolution. The promise resolution process in the Promises/A+ specification contains the following clause:
onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x)
The ES6 promise specification (promises unwrapping) contains a similar clause.
This mandates that when a resolve operation occurs: either in the promise constructor, by calling Promise.resolve or in your case in a then chain a promise implementation must recursively unwrap the returned value if it is a promise.
In practice
This means that if onFulfilled (the then) returns a value, try to "resolve" the promise value yourself thus recursively waiting for the entire chain.
This means the following:
promiseReturning().then(function(){
alert(1);
return foo(); // foo returns a promise
}).then(function(){
alert(2); // will only run after the ENTIRE chain of `foo` resolved
// if foo OR ANY PART OF THE CHAIN rejects and it is not handled this
// will not run
});
So for example:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ throw Error(); });
}).then(function(){
alert("This will never run");
});
And that:
promiseReturning().then(function(){
alert(1);
return Promise.resolve().then(function(){ return delay(2000); });
}).then(function(){
alert("This will only run after 2000 ms");
});
Is it a good idea?
It's been the topic of much debate in the promises specification process a second chain method that does not exhibit this behavior was discussed but decided against (still available in Chrome, but will be removed soon). You can read about the whole debate in this esdiscuss thread. This behavior is for pragmatic reasons so you wouldn't have to manually do it.
In other languages
It's worth mentioning that other languages do not do this, neither futures in Scala or tasks in C# have this property. For example in C# you'd have to call Task.Unwrap on a task in order to wait for its chain to resolve.
Let's start with an easy perspective: "chainPromises" returns a promise, so you could look at it this way:
// Do all internal promises
var cp = chainPromises();
// After everything is finished you execute the final "then".
cp.then(function(val) {
console.log(val);
});
Generally speaking, when returning a promise from within a "then" clause, the "then" function of the encapsulating promise will be marked as finished only after the internal "then" has finished.
So, if "a" is a promise, and "b" is a promise:
// "a"'s "then" function will only be marked as finished after "b"'s "then" function has finished.
var c = a.then(function () {
return b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
So the output will be:
B!
Done!
Notice btw, that if you don't "return" the internal promise, this will not be the case:
// "a"'s "then" function will only be marked as finished without waiting for "b"'s "then" to finish.
var c = a.then(function () {
// Notice we're just calling b.then, and don't "return" it.
b.then(function () {
console.log("B!");
};
};
// c is a promise, since "then" always returns a promise.
c.then(function() {
console.log("Done!");
};
Here we can't know what would be outputted first. It could be either "B!" or "Done!".
Please check the below example regarding how promises works:
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
console.log('person1: shoe ticket');
console.log('person2: shoe ticket');
const promiseGirlFriendBringingTickets = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ticket');
}, 3000);
});
promiseGirlFriendBringingTickets.then((t) => {
console.log(`person3: show ${t}`);
})
console.log('person4: shoe ticket');
console.log('person5: shoe ticket');
Promise then return promise object, not promise's resolved value. I forked your JsFiddle, and added some of mine try this.
promise.then is executed right after that promise object is resolved.
I do not know how this is done in actual promises libraries, but I was able to re-create this functionality in the following way:
1) each promise has a waitingPromises property;
2) then method returns a new promise, and the original promise's waitingPromises property points to the new promise.
In this way, the chain of .then()s creates a structure that is similar to a linked list or rather a tree (each promise can have several waiting promises). A promise can be resolved only after its 'parent' promise has been resolved. The .then method itself is executed immediately, but the corresponding promise that it creates is resolved only later.
I am not sure this is a good explanation and would love to learn about other possible approaches.
Normally code is synchronous - one statement executes like (fileopen) and there is a guarantee that the next statement will execute immediately afterwards like filewrite()
but in asynchronous operations like nodejs, you should assume that
you have no idea when the operation will complete.
You can't even assume that just because you send out one request first, and another request second, that they will return in that order
Callbacks are the standard way of handling asynchrnous code in JavaScript
but promises are the best way to handle asynchronous code.
This is because callbacks make error handling difficult, and lead to ugly nested code.
which user and programmer not readble easily so promises is the way
You can think of Promise as a wrapper on some background task. It takes in a function which needs to be executed in the background.
The most appropriate place to use a promise is where some code is dependent on some background processing and it needs to know the status of the background task which was executed. For that, the background task itself accepts two callback resolve and reject in order to convey its status to the code which is dependent on it. In layman terms, this code is the one behind it in the promise chain.
When a background task invokes resolve callback with some parameter. it's marking the background operation successful and passing the result of the background operation to the next then block which will be executed next. and if it calls reject, marking it as unsuccessful then the first catch block will be executed.
In your custom promise, you can pass an error obj to the reject callback so that next catch block is aware of the error happened in the background task.

Can a function either return a promise, or not?

So that the caller of the function (the user of the service) can use .then if he wants to do something with the information the function generates. If he doesn't care when it gets done, as long as it gets done sometime, he can just call the function without any .then infrastructure.
Will this work? I don't want to get into a situation where it will work in my tests, but in some obscure situation that doesn't happen very often, it will fail.
Hmm. I guess what I mean is this. If I am writing the routine that returns the promise, I have to say:
return new Promise(function (resolve, reject) { ... });
If my caller doesn't say:
.then(function () { ... }, function () { ... });
what will happen? I will at some point call resolve() or reject(), and resolve and reject won't be defined. Does the Promise constructor supply some default (do nothing) definition?
I suppose if I am a crazy person, I can say in my callee function:
(resolve || function () {})();
A function that returns a promise will do what you'd like it to do.
Given a function B():
If the user does not chain B().then(), they will get the answer eventually whenever it is done. It is up to them to handle the fact that they don't know when the value is populated. That is to be expected.
If the user does chain B().then(), they will have a nice and easy way to control what happens once the value is returned.
You do not need to worry about weird edge cases. A function that returns a promise is a clear and straightforward contract.
As with all functions in Javascript, the caller is free to ignore a return value. The Javascript garbage collector will take care of objects or values that are no longer in use.
So, if the caller of some async operation that returns a promise really doesn't care when it's done OR if there are errors, then the caller is free to just ignore the returned promise. Nothing bad happens (other than the fact that you may never know there are errors).
The part of your question that does not seem to be cool with this is where you say: "If he doesn't care when it gets done, as long as it gets done sometime". If you are ignoring async errors, then this may not actually get done sometime and you may never know that. In this case, it might be more appropriate to do:
someAsyncFunc(...).catch(function(err) {
console.err(err);
// so something meaningful with the error here
});
Unless you specifically need to wrap a legacy API, using the Promise constructor is an antipattern. Use the Promise factories instead, or if using bluebird, see if you can use bluebird's promisify on the legacy function.
You also seem to be misunderstanding what the parameters to the Promise constructor function argument are. They are not the callbacks, they are the functions that settle the Promise. The Promise itself will worry about notifying any callbacks, if they exist.
Also, if your function sometimes returns a Promise, and sometimes does not, you might crash any code that assumes it can call .then on your function's return value. Don't do that.
If your computation may be async, always return a Promise. If you want to return a value that is already settled, then return Promise.resolve(theValue).

Break out of a Promise "then" chain with errorCallback

-- 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
What 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!

multiple functions inside of angular then()

Sometimes I see more than two functions separated by comma, inside of promise then() in AngularJs. Could anyone here help to explain what the structure mean?
e.g.
then(function(response){..}, function(response){..}, function(response){..}, function(response){..});
I understand that, if there are two functions inside of then(). The first function will run if it fulfill the promise, otherwise the second will run if there is any error occurs. This structure doesn't look like chained promise either...
Thank you very much for any help here :-)
Well:
The first function is the fulfillment handler, it will execute when the promise resolves to a value (normally).
The second function is the rejection handler, it will execute when the promise resolves with an error by rejecting (or throwing an exception in a handler).
The third function is for progress, this is a nonstandard and deprecated feature that will never be a part of ECMAScript promises - it is best to avoid it altogether since it does not compose well. It is also not supported in Angular's new $q API.
Anything past the third function passed in is ignored by the handler and will have no effect.
Here is an example for all three being called:
var good = $q.when(3);
good.then(x => console.log("Successful"));
var bad = $q.reject(Error("Bad")); // always reject with errors
bad.then(null, x => console.log("Failed"));
var d = $q.defer(); // don't do this like... ever
d.promise.then(null, null, x => console.log("Progressed"));
d.notify("event notification"); // never use this in real code ;)

What does "Promise fires on the same turn of the event loop" mean?

New to NodeJS. Going through the promise tutorial ('promise-it-wont-hurt') I have the following script:
var Q = require('q');
var deferred = Q.defer();
deffered.resolve('SECOND');
deffered.promise.then(console.log);
console.log('FIRST');
The output:
FIRST
SECOND
I don't get it, I would have thought that since resolved is fired first I should see second first.
They explain that this happens because of 'Promise fires on the same turn of the event loop'. I don't understand what that means...
Basically, the point is that the promise's then handler will not run before the current flow of code has finished executing and control is returned to the execution environment (in this case Node).
This is an important characteristic of Promises/A+ compliant promises because it ensures predictability. Regardless of whether the promise resolves immediately:
function getAPromise() {
var Q = require('q');
var deferred = Q.defer();
deferred.resolve('SECOND');
return deferred.promise;
}
getAPromise().then(console.log);
console.log('FIRST');
or whether it resolves after 10 seconds:
function getAPromise() {
var Q = require('q');
var deferred = Q.defer();
setTimeout(function () {
deferred.resolve('SECOND');
}, 10000);
return deferred.promise;
}
getAPromise().then(console.log);
console.log('FIRST');
you can be assured that FIRST will always be logged first.
This is discussed at length in chapters 2 and 3 of You don't know JS - async & performance. Asynchronous operations that sometimes run asynchronously and sometimes run synchronously are called Zalgos, and they are not considered to be a good thing.
It's important to note that the widely used promises in jQuery do not obey this behavior and have a number of other problems as well. If you find yourself with a jQuery promise, wrap it in a proper promise and proceed:
Q($.ajax(...)).then(breatheWithEase);
They explain that this happens because of 'Promise fires on the same turn of the event loop'. I don't understand what that means...
Me neither, imho this part doesn't make much sense. It probably should mean that when you call resolve or reject, the promise is settled immediately, and from then on will not change its state. This has nothing to do with the callbacks yet.
What is more important to understand is the next sentence in that paragraph:
You can expect that the functions passed to the "then" method of a promise will be called on the NEXT turn of the event loop.
It's like a simple rule of thumb: then callbacks are always called asynchronously. Always, in every proper promise implementation; this is mandated by the Promises/A+ specification.
Why is this? For consistency. Unlike in your example snippet, you don't know how or when a promise is resolved - you just get handed it back from some method you called. And it might have already been resolved, or it might be still pending. Now you call the promise's then method, and you can know: it will be asynchronous. You don't need to deal with cases that might be synchronous or not and change the meaning of your code, it simply is always asynchronous.

Categories

Resources