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:
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.
Note the example executor function in
var p = new Promise(function(res, rej){});
is incomplete. An actual executor function supplied to the Promise constructor must call its first argument (res
) to resolve the constructed promise, or its second argument (rej
) to reject the promise. These calls are normally made asynchronously but don't have to be in ES6.
When a promise is resolved with a Promise object (or any object with a .then
property which is a function) nothing happens until the promise object supplied in resolution itself becomes fulfilled or rejected. Fulfilled values are passed to .then
onFulfilled
handlers, rejected values are passed to .then
onRejected
handlers/listeners/callbacks (depending on your terminology).
But when a promise is resolved with a non promise (like) object, listeners supplied as the first parameter to .then
are called with the resolution value.
When a promise is rejected with any value, listeners supplied as the second parameter to .then
, or first parameter to .catch
, are called with the rejected value.
.catch
is a euphemism for calling .then
with the supplied argument as second parameter and omitting the first parameter, as in
Promise.prototype.catch = function( listener) { return this.then(null, listener);};
The behavior of .then
registered onFulfill
and onReject
functions is the same. To reject a chained promise throw an error. To fulfill a chained promise return a non promise value. To hold up a chained promise return a promise (or promise like) object.
(Update) When a parameter supplied to .then( onFulfill, onReject)
is missing or not a function object, processing is equivalent to supplying a dummy function from:
function onFulfill( data) { return data;}
function onReject( err) { throw err;}
This is the usual case when calling then
or catch
with a single argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With