Reputation: 45
I'm trying to build a simple CRUD application. User has a profile page and can fill the fields about himself and save them. My question is:
I'm using axios for http requests (in Redux application):
export const createCard = (data) => (dispatch) =>
axios.post('/api/cards', data)
.then(
response => dispatch({
type: actions.CREATE_CARD_SUCCESS,
card: response.data
})
error => dispatch({
type: actions.CREATE_CARD_FAILURE,
message: error.message
})
)
.then(() => /* do something here, if no error occur */);
And after request has finished successfully, i want to do something in then method. but it fires always, even if an error has occur
This can be achieved like this:
export const createCard = (data) => (dispatch) =>
axios.post('/api/cards', data)
.then(
response => {
dispatch({
type: actions.CREATE_CARD_SUCCESS,
card: response.data
});
},
error => {
dispatch({
type: actions.CREATE_CARD_FAILURE,
message: error.message
});
return error;
}
)
.then(error => {
if (!error) {
/* do something here, if no error occur */
}
});
But it is too much boilerplate.
In this case, Jquery.ajax is convenient.
$.ajax()
.done()
.fail()
.always()
.then(() => { /** this callback will be fired if no error occur **/})
How can i simulate this behaviour in axios or fetch api?
Upvotes: 4
Views: 1925
Reputation: 7286
If you omit the error handler in a then
callback, any errors will be propagated to the next callback that does have one (if any). Add a catch block to the end of your chain to perform error handling for the whole chain:
axios.post('/api/cards', data)
.then(response => {
dispatch({
type: actions.CREATE_CARD_SUCCESS,
card: response.data
});
}).then(() => {
// this block won't be executed if there is a post error
}).catch(error => {
// handle post error
dispatch({
type: actions.CREATE_CARD_FAILURE,
message: error.message
});
// if we wished to propagate the error to the caller, skipping
// subsequent then blocks, we could re-raise it here by throwing it:
// throw error;
}).then(() => {
// this block will be executed after the catch handler unless
// it raises another error by throwing an exception
});
Upvotes: 1
Reputation: 707366
It appears that you have a promise reject handler that handles the rejection and accidentally turns the promise from rejected back to resolved and thus your following .then()
handlers get called even though and error occurs.
When you create a promise error handler with either .catch()
or with the second callback to .then()
like this:
p.then(result => {
// do something with result here
}, err => {
console.err(err);
}).then(result => {
// this will always get fired because you "ate" the error in the previous catch handler
});
And, you handle the error without rethrowing or without returning a rejected promise, then the promise infrastructure considers that you have "handled" the error and the parent promise becomes resolved (no longer rejected). So, thus any following .then()
handlers will get called, even though an error occurred earlier in the chain.
If you want to do something on the error (like log it or execute some other logic), but you want the promise to stay rejected, then you have to either rethrow the error or return a rejected promise. That's the only way to keep the chain rejected.
Though the code in your question appears to be missing a comma, it appears like this is supposed to be the second argument to a .then()
handler and thus will get called when the promise is rejected:
error => {
dispatch({
type: actions.CREATE_CARD_FAILURE,
message: error.message
});
return error;
}
Since you are only doing a normal return error
, this will change the promise to be resolved (no longer rejected) and thus the following .then()
handler gets called.
To keep the promise rejected, you can rethrow the error (with ES6 standard's compliant promises) or you can return a rejected promise (with either jQuery .then()
handlers or ES6 standard's compliant promises):
error => {
dispatch({
type: actions.CREATE_CARD_FAILURE,
message: error.message
});
// keep the promise rejected
return Promise.reject(error);
}
Note: This is very analogous to how try/catch works for regular synchronous code. When you do a catch()
, the exception is handled and does not propagate up unless you rethrow it. Same for promise catch handlers.
Upvotes: 2