I'm having some issues with the way im handling errors in Vue. Currently im using a try/catch block in VueX to make some async calls. The catch block handles adding the error to a global toast. this is working very well.
async add({ dispatch }, form) {
try {
await firebase.add(form)
dispatch('getUpdatedList')
} catch (error) {
// Use the global error handle to handle the error
dispatch('error', error)
}
},
error ({ dispatch, commit }, errorMessage) {
console.log(errorMessage)
commit('ERROR', errorMessage)
}
// Add the Errors here
ERROR (state, val) {
state.errors = [val, ...state.errors]
},
The issue I have is this: When that error is caught in the block, it doesn't allow the errors to propagate to the components, so I can't handle the error in the component the way I would like. For example, if the client submits a form, but somehow that fails, the then block of a promise will still execute. So i can't reset the form, or stop a redirect, or do some UI tidy up on the client.
this.$store
.dispatch('add', this.data)
.then(() => {
//This gets hit no matter what the result
this.showSuccess = true
})
.catch(() => {
// More UI stuff
//Can only hit this when rethrowing the error
this.showLoading = false
this.showRegisterButton = true
})
I know that I can get around this by rethrowing the error, but that doesn't seem like the best way forward, as I've always believed that rethrowing an error is bad practice (although here it seems like a decent solution) Is there something simple that im missing?
This should be fine, with just one amendment.
You can re-throw the error to allow parent to catch using throw error
async add({ dispatch }, form) {
try {
await firebase.add(form)
dispatch('getUpdatedList')
} catch (error) {
// Use the global error handle to handle the error
dispatch('error', error)
// throw the handled error for another handler to catch
throw error
}
}
Related
I have the following code:
const getJSON = async function(url, errorMsg = 'Something went wrong') {
return fetch(url).then(response => {
if (!response.ok) throw new Error(`${errorMsg} (${response.status})`);
return response.json();
});
};
const outerFunc = async function() {
try {
let x = await getJSON();
} catch (err) {
console.log(err);
}
}
outerFunc();
I tried to run the code inside the console and get an error:
VM60:2 Fetch API cannot load chrome://new-tab-page/undefined. URL scheme "chrome" is not supported.
I want to understand if the try/catch block that surrounds the **outerFunc ** function can catch an error that will come from the called async function (asyncFunction) , or asyncFunction should handle its error by himself. I know that in Java it's ok to "propagate" the error. What is the correct behavior in JS?
Generally, you want to catch errors at a point where you can do something useful in response to the error. Often, this is not the point where the API is called, but somewhere further up the call stack. Allowing errors to naturally propagate upwards to where they can be handled reasonably is a fine idea.
For example, in a real application, if there's a catch block which is composed solely of a console.log, that's often (not always) an indication that the error should be caught somewhere else. When there's an error, one will often want to inform the user that there was a problem, so the following sort of pattern is very common:
getAPI()
.then(populateWithResults)
.catch((error) => {
const div = document.querySelector('.errors').appendChild(document.createElement('div'));
div.textContent = 'There was an unexpected error: ' + error.message;
});
where getAPI does no catching of its own, but simply allows the caller to handle possible errors - similar to what your getJSON function is doing.
Usually you'll only want one point where an error is caught, but occasionally you might want to catch it in multiple places - for example, perhaps a sub-component wants to do something in particular when an error is encountered, but it also wants to notify the callers that there's a problem. In such cases, re-throwing the error could look like:
const makeSubComponent = () => {
const componentContainer = document.querySelector('.container');
const populateSubComponent = () => {
// ...
};
return getAPI()
.then(populateSubComponent)
.catch((error) => {
componentContainer.textContent = 'Something went wrong...'
throw error; // Inform the caller of makeSubComponent of the error
});
};
allowing both makeSubComponent and its caller to deal with possible problems.
I am using Axios in my React-Native app to communicate with a Nodejs backend, and am using react-redux dispatch to call the actions that will utilize Axios. However, no matter what I try I land up getting "Unhandled Promise Rejection" anytime there is an error of any sort. This is frustrating me so much I'm about to give up on Axios and just go back to using fetch. I've googled this problem (which seems to be very common indeed), but have not found any solid solution yet.
Here is an example of how I'm using Axios in my actions to send requests to my Nodejs backend server:
export const getAppointments = (userId) => {
return async (dispatch) => {
const request = axios
.get(`${SERVER_BOOKINGS}/upcoming_appointments/${userId}`)
.then((response) => {
let ourPayload = {};
ourPayload.success = response.data.success;
if (ourPayload.success) {
ourPayload.bookings = response.data.bookings;
dispatch({
type: GET_UPCOMING_APPOINTMENTS,
payload: ourPayload,
});
}
})
.catch((err) => {
console.log("caught an error, HERE:", err);
//throw err
});
};
};
And here is the code I'm using to call this action:
const getAppointments = async () => {
try {
await dispatch(
bookingActions.getAppointments(userObject.userData.userId)
);
} catch (error) {
console.log("we actually caught an axios error client side!");
}
}
If I leave the code exactly as above and I deliberately cause an error response from my Nodejs code , I get a console.log message saying "caught an error, HERE", but get nothing from the catch block where I actually dispatch the action (2nd block of code).
If I uncomment out the throw err line in the first catch block, I still get the console.log, still get nothing from the second catch block.... but now I get an Unhandled Promise Rejection warning.
Right now, this code works very well as long as there isn't an error, and is completely worthless anytime there is an one. In all honestly, I don't know whether the issue is one with axios, react-redux dispatch or just a failure on my part to understand the way Promises are meant to work, but I've wasted untold hours trying to figure out what should be a really simple matter of catching errors... and I'm falling behind schedule on this project because of it. Any advice/help would be greatly appreciated!
I think that the problem is caused since "bookingActions.getAppointments" is not a Promise function so there is no need to "try-catch" it.
try to change it like this:
const getAppointments = () => dispatch(bookingActions.getAppointments(userObject.userData.userId));
In learning to write in JavaScript with Promises, I'm encountering two different ways of dealing with errors. One is to use a catch, as in this example:
axios.post('/someapi', {
somedata1: 'foo'
})
.then((result) => {
console.log(result);
})
.catch((exception) => {
console.log(exception);
});
The other is to have a clause in the then for the rejected case:
axios.post('/someapi', {
somedata1: 'foo',
})
.then((response) => {
console.log(response);
}, (error) => {
console.log(error);
});
Some authors seem to use one approach, other authors use the other, and it's not clear to me why. Are there situations in which it's necessary or desirable to use one or the other?
(The example above uses axios, but that's just for the purposes of providing a code example. This question is not about axios.)
With Javascript Promises, are there best practices regarding the use of “error” versus catch clauses?
There is no universal "best practice" for that question because it depends upon what specific behavior you want your code to have. As others have mentioned, you get a different behavior in a few ways.
Some authors seem to use one approach, other authors use the other, and it's not clear to me why. Are there situations in which it's necessary or desirable to use one or the other?
Yes, there are situations to use one or the other. They provide potentially different behaviors. Only if you're 200% sure that your successHandler in .then(successHandler) can never throw or return a rejected promise, would there be no meaningful difference.
As a summary:
When using p.then(successHandler).catch(errorHandler), errorHandler will get errors that occur either from a rejected p or from an error or rejection from the successHandler.
When using p.then(successHandler, errorHandler), errorHandler will be called from a rejection of p and will NOT get called from an error or rejection from the successHandler.
Different behaviors that are useful for different circumstances.
In this .catch() example below, the .catch() will catch an error that occurs (either accidentally from a coding error, a thrown exception or when returning some other promise that rejects).
Promise.resolve("hello").then(greeting => {
console.log("throwing error");
throw new Error("My .then() handler had an error");
}).catch(err => {
// will get here
console.log("Caught error in .catch()\nError was: ", err.message);
});
But, when using the second argument to .then(), that error from the .then() handler will not be caught:
Promise.resolve("hello").then(greeting => {
console.log("throwing error");
throw new Error("My .then() handler had an error");
}, err => {
// won't get here
console.log("Caught error in .catch()\nError was: ", err.message);
});
So, sometimes you want an error that might occur in the .then() handler to hit this immediate error handler and sometimes you don't want it to hit that error handler because you want that error handler to only process errors from the original promise and you have some other catch handler later in the promise chain that will deal with this error.
Recommendation
In general, I would advise that you start out with the .catch() handler because it catches more errors and does not require that there be some other .catch() handler elsewhere in the promise chain in order to be safe. Then, you switch to the .then(successHandler, errorHandler) form if you explicitly don't want this errorHandlerto be called if there's another error in the successHandler AND you have somewhere else in the promise chain where an error in the successHandler would get caught or handled.
Both the syntaxes work out of the box. But the first one has an advantage that the Catch block is able to catch an error thrown by the Promise Rejection as well as an error thrown by then block.
Here is the Example you can try in Node and you will have a better idea about it.
function x () {
return new Promise((resolve, reject) => {
return resolve('Done...');
});
}
x()
.then(response => {
console.log('RESPONSE---', response)
throw 'Oops...Error occurred...';
})
.catch(error => console.log('ERROR---', error));
x()
.then(
response => {
console.log('RESPONSE---', response)
throw 'Oops...Error occurred...';
},
error => console.log('ERROR---', error)
);
Right now I am working with code resembling a structure like this:
doThis().then(() => {
doThat().then([...]).catch(e => {
console.log('internal catch');
});
}).catch(e => {
console.log('external catch');
});
If the interior function doThat() ends up returning an exception, will the internal catch, the external catch, or both send messages?
In your case, only the internal catch will handle the error thrown by the doThat function call. The external doThis function won't be aware of what's going on at all. If you want the external catch to handle it, then you'll have to reorganise your code a bit.
doThis().then(() => {
// By returning the internal promise, the external one will
// now be able to handle both success and error.
return doThat().then([...]).catch(e => {
console.log('internal catch');
// Rethrowing will ensure that the error will propagate to the external handler.
// Otherwise, handling the error in the catch function will make
// the promise successful again.
throw e
});
}).catch(e => {
console.log('external catch');
});
Hi i am using angular 5 and i am writing a global handler for the same which looks like following.
#Injectable()
export class ErrorsHandler implements ErrorHandler {
constructor(
private injector: Injector,
) { }
handleError(error: Error | HttpErrorResponse) {
const router = this.injector.get(Router);
const zone = this.injector.get(NgZone);
console.log('Here')
console.log(error)
if (error instanceof HttpErrorResponse) {
// Client Error Happend
zone.run(() => router.navigate(['/error'], { queryParams: { error: JSON.stringify(error) } }))
} else {
// Log the error anyway
router.navigate(['/error'], { queryParams: { error: JSON.stringify({ message: 'Failed' }) } });
}
}
}
Everything works fine in Observable world ie if i do a failed http call like following
fireServerError() {
this.httpService
.get('https://jsonplaceholder.typicode.com/1')
.subscribe(data => console.log('Data: ', data));
}
and if the server call fails i get an error object properly as shown in the console image
But instead of that if i change it to a promise using toPromise(), like following
fireServerError() {
this.httpService
.get('https://jsonplaceholder.typicode.com/1')
.toPromise();
}
i get the following string stack trace instead of error Object itself
What am i doing wrong. How to throw/get the error object in case of unhandled promise rejections. Please help. I am stuck;
Please find the stackblitz link Here
Once you use .toPromise(), you are essentially putting the behavior into a different execution context (read ECMAScript 10.4), which means that errors must be handled in/around the new execution context rather than having them bubble up in Angular like you are expecting.
I can't say I entirely follow your example code (is fireServerError always supposed to throw an error via an HTTP call?), but it seems like you want to try to execute promises without local error handling, but rather to have any error from a promise bubble up to the angular error handling. I'm not sure I'd recommend that, I believe it's best-practice to handle promise errors locally (i.e. using Promise.prototype.catch or a try/await/catch block when you create the promise).
That being said, error handling is of course a complicated topic and if you are dead set on just handling all errors at the global level then you can try using a global window event handler to catch all unhandled promise rejections and handle them there:
window.addEventListener("unhandledrejection", event => {
event.preventDefault(); // prevent the default promise rejection behavior
console.error(event); // do whatever you want with the error
}, false);
The MDN guide on promises may also help clear some things up, hope that helps!