try...catch if a function throws error NodeJS - javascript

I'm trying to handle a function if it throws an error: create.js
function Apple() {
createDB() //function that saves into db
}
createDB.js
function createDB() {
const Info = new collection(data)
Info.save()
}
Suppose createDB function throws an error when required field in the db is not present. I want to handle such errors.
I tried:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch{
function that handles error
}
}
and I also tried:
function createDB() {
return new Promise((resolve, reject) => {
if some condition met{
const Info = new collection(data)
Info.save()
}else{
reject(error)
}
})
}
But it still doesn't goes to the catch block. I'm relatively new to the topic so any suggestions will be really helpful. Basically I want to handle the errors if a function throws error, and it should go to catch block.

You are actually not following the correct syntax. Check out the sampe one:
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// expected output: ReferenceError: nonExistentFunction is not defined
// Note - error messages will vary depending on browser
}
Your updated code with try-catch should follow the above syntax:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch (error) {
function that handles error
// here you should log errors or use the logging lib
}
}
Also, if you are using promises, you can follow this approach:
function createDB() {
return new Promise((resolve, reject) => {
if (condition) {
const Info = new collection(data);
Info.save().then(data =>{ resolve(data)})
.catch(e => {console.error(e)}) // handle this promise also
}
else {
reject(error);
}
})
}
Also, you need to understand when to use try-catch block and when to use promises. The try, catch blocks are used to handle exceptions (a type of an error) when the code is synchronous. You should use Promises only for asynchronous functions and nothing else.

Use this sample piece of code
Within try block we write our code which we want to execute
If any error occur controller goes to catch block
In catch block we also receive error
try {
//Here write your code which you want to execute
return true
} catch (error) {
//if there is an any error controller will come into this block and show error
console.error(error);
return false
}

Related

JavaScript: differences between async error handling with async/await and then/catch

Just wanted to preemptively say that I am familiar with async/await and promises in JavaScript so no need to link me to some MDN pages for that.
I have a function to fetch user details and display it on the UI.
async function someHttpCall() {
throw 'someHttpCall error'
}
async function fetchUserDetails() {
throw 'fetchUserDetails error'
}
function displayUserDetails(userDetails) {
console.log('userDetails:', userDetails)
}
async function fetchUser() {
try {
const user = await someHttpCall()
try {
const details = await fetchUserDetails(user)
returndisplayUserDetails(details)
} catch (fetchUserDetailsError) {
console.log('fetching user error', fetchUserDetailsError)
}
} catch (someHttpCallError) {
console.log('networking error:', someHttpCallError)
}
}
It first makes HTTP call via someHttpCall and if it succeeds then it proceeds to fetchUserDetails and it that succeeds as well then we display the details on Ui via returndisplayUserDetails.
If someHttpCall failed, we will stop and not make fetchUserDetails call. In other words, we want to separate the error handling for someHttpCall and it’s data handling from fetchUserDetails
The function I wrote is with nested try catch blocks which doesn't scale well if the nesting becomes deep and I was trying to rewrite it for better readability using plain then and catch
This was my first atttempt
function fetchUser2() {
someHttpCall()
.then(
(user) => fetchUserDetails(user),
(someHttpCallError) => {
console.log('networking error:', someHttpCallError)
}
)
.then(
(details) => {
displayUserDetails(details)
}, //
(fetchUserDetailsError) => {
console.log('fetching user error', fetchUserDetailsError)
}
)
}
The problem with this is that the second then will run i.e. displayUserDetails even with someHttpCall failing. To avoid this I had to make the previous .catch blocks throw
so this is the updated version
function fetchUser2() {
someHttpCall()
.then(
(user) => fetchUserDetails(user),
(someHttpCallError) => {
console.log('networking error:', someHttpCallError)
throw someHttpCallError
}
)
.then(
(details) => {
displayUserDetails(details)
}, //
(fetchUserDetailsError) => {
console.log('fetching user error', fetchUserDetailsError)
}
)
}
However now the second catch will get called as a result of the throw. So when the someHttpCall failed, after we handled the someHttpCallError error, we would enter this block (fetchUserDetailsError) => { console.log('fetching user error', fetchUserDetailsError) } which is not good since fetchUserDetails never gets called so we shouldn't need to handle fetchUserDetailsError (I know someHttpCallError became fetchUserDetailsError in this case)
I can add some conditional checks in there to distinguish the two errors but it seems less ideal. So I am wondering how I can improve this by using .then and .catch to achieve the same goal here.
I am wondering how I can improve this by using .then and .catch to achieve the same goal here
You don't get to avoid the nesting if you want to replicate the same behaviour:
function fetchUser2() {
return someHttpCall().then(
(user) => {
return fetchUserDetails(user).then(
(details) => {
return displayUserDetails(details)
},
(fetchUserDetailsError) => {
console.log('fetching user error', fetchUserDetailsError)
}
)
},
(someHttpCallError) => {
console.log('networking error:', someHttpCallError)
throw someHttpCallError
}
)
}
(The exact equivalent to try/catch would use .then(…).catch(…) instead of .then(…, …), but you might not actually want that.)
The function I wrote is [nested] which doesn't scale well if the nesting becomes deep and I was trying to rewrite it for better readability […]
For that, I would recommend to combine await with .catch():
async function fetchUser() {
try {
const user = await someHttpCall().catch(someHttpCallError => {
throw new Error('networking error', {cause: someHttpCallError});
});
const details = await fetchUserDetails(user).catch(fetchUserDetailsError => {
throw new Error('fetching user error', {cause: fetchUserDetailsError});
});
return displayUserDetails(details);
} catch (someError) {
console.log(someError.message, someError.cause);
}
}
(The cause option for Error is still quite new, you might need a polyfill for that)
I can add some conditional checks in there to distinguish the two errors but it seems less ideal.
Actually, that sounds like an ideal situation. That means that you don't have to nest any try / catch blocks which could make you code a lot more readable. This is one of the things that async / await is meant to solve.
A solution could be is to create custom errors by extending the Error interface to be able to determine how and where the error occurs.
class CustomError extends Error {
constructor(name, ...args) {
super(...args)
this.name = name
}
}
Throw your errors within the functions that correspond with the error.
async function someHttpCall() {
throw new CustomError('HttpCallError', 'someHttpCall error');
}
async function fetchUserDetails(user) {
throw new CustomError('UserDetailsError', 'fetchUserDetails error')
}
Now you can control your error flow by checking the name property on the error to differentiate your errors.
async function fetchUser() {
try {
const user = await someHttpCall()
const details = await fetchUserDetails(user)
return displayUserDetails(details)
} catch (error) {
switch(error.name) {
case 'HttpCallError':
console.log('Networking error:', error)
break
case 'UserDetailsError':
console.log('Fetching user error', error)
break
}
}
}
I've been inspired by Rust's Result type (which forces you to handle every potential error along the way).
So what I do is handle exceptions in every individual function, and never allow one to throw, instead returning either an Error (if something went wrong) or the desired return value (if no exception occurred). Here's an example of how I do it (comments included):
TS Playground
If you aren't familiar with TypeScript, you can see the JavaScript-only version of the following code (with no type information) at the TypeScript Playground link above (on the right side of the page).
// This is the code in my exception-handling utility module:
// exception-utils.ts
export type Result <T = void, E extends Error = Error> = T | E;
export function getError (value: unknown): Error {
return value instanceof Error ? value : new Error(String(value));
}
export function isError <T>(value: T): value is T & Error {
return value instanceof Error;
}
export function assertNotError <T>(value: T): asserts value is Exclude<T, Error> {
if (value instanceof Error) throw value;
}
// This is how to use it:
// main.ts
import {assertNotError, getError, isError, type Result} from './exception-utils.ts';
/**
* Returns either Error or string ID,
* but won't throw because it catches exceptions internally
*/
declare function getStringFromAPI1 (): Promise<Result<string>>;
/**
* Requires ID from API1. Returns either Error or final number value,
* but won't throw because it catches exceptions internally
*/
declare function getNumberFromAPI2 (id: string): Promise<Result<number>>;
/**
* Create version of second function with no parameter required:
* Returns either Error or final number value,
* but won't throw because it catches exceptions internally
*
* The previous two functions work just like this, using the utilities
*/
async function fetchValueFromAPI2 (): Promise<Result<number>> {
try {
const id = await getStringFromAPI1(); // Error or string
assertNotError(id); // throws if `id` is an Error
return getNumberFromAPI2(id); // Error or number
}
catch (ex) {
return getError(ex);
}
}
async function doSomethingWithValueFromAPI2 (): Promise<void> {
const value = await fetchValueFromAPI2(); // value is number or Error
if (isError(value)) {
// handle error
}
else console.log(value); // value is number at this point
}

Catching errors from one function inside another JavaScript React

I have two functions, login (in fileB.js):
export const login = async (data) => {
try {
const response = await auth.login(data);
return response;
} catch (e) {
return new Error(e);
}
};
and loginProcess (in fileA.js):
const loginProcess = (data) => {
login(data)
.then((response) => {
if (response.status === 200) {
}
})
.catch((e) => {
setError(true);
});
};
If I have an error inside login() function it returns new Error(e) but inside loginProcess() the error from login() is not caught by catch but with then. I need to catch the new Error from login() inside catch in loginProcess(), how can I fix it?
You are converting promise rejection into promise fulfilment by returning an error object.
Retuning a non-promise value from the catch block will fulfil the promise returned by the login function with the return value of the catch block.
To reject the promise returned by the login function:
Re-throw the error caught by the catch block, or
Remove the try-catch block from the login function and let the calling code handle the error.
login function could be re-written as:
export const login = (data) => {
return auth.login(data);
};
I suggest that you choose the second option and re-write the login function as shown above. There is no need for a catch block that just re-throws the error.

How to catch all internal errors from external code in JavaScript?

I have the following call to an API (an npm module running in Node.js) in a JavaScript file in which I would like to catch all errors so can gracefully handle them. But if I e.g. pass a bad API-KEY or a city name that does not exist, there is an error in the internal code of the API which is not caught by the try/catch:
const weather = require('openweather-apis');
const getTemperature = (city, cbSuccess, cbFailure) => {
try {
weather.setLang('de');
weather.setCity(city);
weather.setUnits('metric');
weather.setAPPID('BADKEY');
weather.getTemperature((err, temperature) => {
if (err) {
console.log(err);
} else {
console.log(`The temperature in ${city} is ${temperature}° C.`);
}
});
} catch (error) {
console.log('there was an error');
}
}
getTemperature('Berlin');
Rather, an error is displayed and execution stops:
C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:162
return callback(err,jsonObj.main.temp);
^
TypeError: Cannot read property 'temp' of undefined
at C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:162:40
at IncomingMessage.<anonymous> (C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:250:18)
at IncomingMessage.emit (events.js:194:15)
at endReadableNT (_stream_readable.js:1125:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
Is there a way in JavaScript to catch all errors as one does in e.g. Java and C#?
I believe that something like this might work:
async execute(weather, city, temperature) {
return await new Promise(function(resolve, reject) {
weather.getTemperature((err, temperature) => {
if (err) {
reject(err);
} else {
resolve(`The temperature in ${city} is ${temperature}° C.`);
}
});
};
}
const getTemperature = async (city, cbSuccess, cbFailure) => {
try {
weather.setLang('de');
weather.setCity(city);
weather.setUnits('metric');
weather.setAPPID('BADKEY');
const res = await execute(weather, city, temperature);
console.log(res);
} catch (error) {
console.log('there was an error');
}
}
You're out of luck if an exception throws in asynchronous code. This will stop execution of the script (as you're seeing above).
The module you are using should possibly handle the error in a better way and pass the error in the callback err parameter. Unless you fork the code or file a bug you're stuck with this.
The same effect can be demonstrated here:
async function testAsyncException() {
try {
setTimeout(() => {
throw new Error("Error in asynchronous code");
}, 100);
} catch (e) {
// This will never be caught...
console.error("testAsyncException: A bad error occurred:", e);
}
}
process.on('uncaughtException', (e) => {
console.log("uncaughtException:", e);
})
testAsyncException();
The try .. catch block around the setTimeout call will not handle the generated exception.
The only way you can "catch" this type of exception is using a process event like so:
process.on('uncaughtException', (e) => {
console.log("uncaughtException:", e);
})
This however should only be used to log and then exit. Trying to recover program state at this point is not a good idea, since the application is in an unknown state.
If you're using a process manager such as the very useful PM2, the script can be automatically restarted on errors.
Conversely if we try the following:
function testSyncException() {
try {
throw new Error("Error in synchronous code");
} catch (e) {
// This will be caught...
console.error("testSyncException: A bad error occurred:", e);
}
}
testSyncException();
We can see that the exception will be caught.
I strongly recommend this excellent article on error handling by the creators of Node.js (Joyent):
https://www.joyent.com/node-js/production/design/errors
It details the best strategies for handling both Operational errors and Programmer errors.
there is an error in the internal code of the API
return callback(err,jsonObj.main.temp);
^
TypeError: Cannot read property 'temp' of undefined
at C:\edward\nwo\jsasync\node_modules\openweather-apis\index.js:162:40
This is clearly a bug in the openweather-apis library. Report it. You hardly will be able to work around it. The library will need to check whether jsonObj and jsonObj.main exist before attempting to access .temp on it, and it should call your callback with an error if the jsonObj doesn't look as expected.

Javascript fetch, catch runs forever

What happens: If I use fetch..catch and calls another function. In that next function if anything crashes. It will be caught in last catch. This will go on so if the next function crashes it will still be caught in the fetch..catch
What I want: When calling myExternalFunction() I want to 'disconnect' from the try..catch that fetch throws.
fetch('mystuff.url')
.then((data)=>{
myExternalFunction();
})
.catch((e)=>{
// all future errors will come here
})
myExternalFunction(){
// This error will be caught by fetch..catch
// we don't want that
crash();
}
Fiddler example to try it
You don't want to chain your catch to the then then, but keep them at the same level:
fetch(...).then(successCallback, failCallback)
Or:
const p = fetch(...);
p.then(successCallback);
p.catch(failCallback);
const p = Promise.resolve('foo');
p.then(() => { throw new Error('noooooo') });
p.catch(() => console.error('caught'));
The difference is that fetch().then().catch() will catch any error produced by either the fetch promise or the then promise; while the above two methods apply the failCallback only to the fetch promise.
When calling myExternalFunction() I want to 'disconnect' from the
try..catch that fetch throws.
Catch the exception of crash in myExternalFunction itself.
fetch('mystuff.url')
.then((data)=>{
myExternalFunction();
})
.catch((e)=>{
// all future errors will come here
})
function myExternalFunction(){
try
{
crash();
}
catch(e)
{
//do nothing
}
}
Or (if modifying external function is not possible) catch the same in then
fetch('mystuff.url')
.then((data)=>{
try
{
myExternalFunction();
}
catch(e)
{
//do nothing
}
})
.catch((e)=>{
// all future errors will come here
})
function myExternalFunction(){
crash();
}
If we don't want to wrap the 'external function' in try..catch (then we need to continue to wrap next call as well and so on. This issue can be noted when e.g. using react with redux thunk. How a fetch..catch captures errors happening somewhere else.
To completly break we need something else as setTimeout. Must be a better way for this.
fetch('mystuff.url')
.then((data)=>{
// this will break out so 'external function' doesn't get caught in catch.
setTimeout(myExternalFunction,1);
})
.catch((e)=>{
// only errors from the fetch
})
function myExternalFunction(){
crash(); // we are happy, it crashes without involving fetch
}
If you want to use catch with fetch I propose to use this solution.
fetch("http://httpstat.us/500")
.then(function(response) {
if (!response.ok) {
throw Error(response.status);
}
return response;
}).then(function(response) {
alert("ok");
}).catch(function(error) {
alert(error);
});

Uncaught (in promise)

I know the problem is usual. I'm using es6 promises, and I have multiple layers.
On runtime, when I don't catch a promise, I have Uncaught (in promise) in my console. But the fact is that I do catch it lower in my code.
Fast simplified example :
LoginApi.js
var loginDaoCall = loginDao.login(username, password);
loginDaoCall
.then(function (res) {
store.dispatch(loginSuccess());
log.log("[loginApi.login] END");
})
.catch(function (err) {
store.dispatch(loginFail());
errorUtils.dispatchErrorWithTimeout(errorLogin);
log.log(err);
});
return loginDaoCall;
loginContainer.js
loginApi.login(user, password).then(() => {
// Change here instead of in render so the user can go back to login page
this.props.history.push(baseUrlRouter + "test");
}); // <- Error here cause I don't CATCH the promise, but I do catch it in my loginapi.js
I know that I could catch doing nothing, but eh. I could also do the history push thing in my API layer, but it is not its responsibility.
How can I avoid the error in my console? Is there a way? I'm even thinking about leaving it like this.
Your problem is that you were returning the rejected loginDaoCall, not the promise where the error was already handled. loginApi.login(user, password) did indeed return a rejected promise, and even while that was handled in another branch, the promise returned by the further .then() does also get rejected and was not handled.
You might want to do something like
// LoginApi.js
return loginDao.login(username, password).then(function (res) {
store.dispatch(loginSuccess());
log.log("[loginApi.login] END");
return true;
}, function (err) {
store.dispatch(loginFail());
errorUtils.dispatchErrorWithTimeout(errorLogin);
log.log(err);
return false;
}); // never supposed to reject
// loginContainer.js
loginApi.login(user, password).then(success => {
if (success) {
// Change here instead of in render so the user can go back to login page
this.props.history.push(baseUrlRouter + "test");
}
});
It sounds like you have an error in your catch block. When the error is thrown there is no 2nd catch block to catch the error in the 1st catch block.
To fix it ...
.then(function (res) {
// some code that throws an error
})
.catch(function (err) {
// some code that throws an error
})
.catch(function (err) {
// This will fix your error since you are now handling the error thrown by your first catch block
console.log(err.message)
});

Categories

Resources