All:
I am pretty new to JS Promise, there is one confuse when it comes to Promise chaining, say I have a promise chaining like:
var p = new Promise(function(res, rej){
})
.then(
function(data){
},
function(err){
})
.then(
function(data){
},
function(err){
})
.catch(
function(err){
})
What confuse me:
- When the function(err) get called and when the catch get called?
- How to resolve and reject in
then
?
Thanks
The formular for using a Promise is:
var p = new Promise(function(resolve, reject) {
var condition = doSomething();
if (condition) {
resolve(data);
} else {
reject(err);
}
});
There is nothing special about .catch
, it is just sugar for .then (undefined, func)
, but .catch
more clearly communicates that it is purely an error handler.
If a Promise
does not resolve and no rejection callback is provided in it, it skips forward to the next .then
in the chain with a rejection callback in it. The rejection callback is the reject(err)
.
For more detailed explanations see: Javascript Promises - There and Back again.
That is: in your example the .catch
only gets called if the preceding rejection callback has an error in it. That is there is an error in the reject(err)
function itself - which has nothing to do with the preceding Promise
not resolving.
You can essentially limit yourself to a rejection callback in the .catch
at you end of the .then
chain. Any Error
in any .then
will then fall through to the .catch
. One subtlety though: any error in the .catch
is not caught.
The important thing to know is that the .then() method is always chained onto a Promise, and it returns a new Promise whose value and resolved/rejected state is based on what the function given to it returned.
In your example, if the original Promise resolves, then the first function in your first .then() will get called with the resolved value. If it returns a value then whatever value it returns will then get ultimately passed into the first function in your second .then(). The function in catch will never get called.
If the Promise rejects, the second function in your first .then() will get called with the rejected value, and whatever value it returns will become a new resolved Promise which passes into the first function of your second then. Catch is never called here either. It's only if the Promise rejects and you keep returning rejected Promises or throwing errors in both your function(err){}
functions that you'll get the function(err){}
in your catch block called.
To resolve in your function(data){}
functions, all you need to do is return a value (or return a Promise/thenable that later resolves).
To reject, you would need to either throw an error, actually cause an error, return a new Promise that eventually rejects, or explicitly return Promise.reject(::some value::)
.
To resolve in your function(err){}
blocks, all you need to do is return a new value. You could also return a Promise, in which case that Promise is what will be returned (eventually resolving or rejecting).
In general, it's not wise to define both the resolved and rejected path in the same .then() though: PROMISE.then(fn).catch(fn)
is a much safer/clearer practice, because then any errors in the first .then() will be caught by catch. If you do PROMISE.then(fn, fn)
instead though, if an error happens in the first function it would NOT get caught by the second: some later chained on method would have to catch it.