Try-catch-rethrow - proper pattern - javascript

If I have such code:
let result;
try {
result = doSomethingThatCanThrow();
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
}
// do something with result if didn't throw
Is this valid pattern in JS? I don't like using let. I prefer const but I can't use it in this case because it won't be available outside try-catch block.
I could put whole code in try block and get rid of let but then it would be harder to read in my opinion:
try {
const result = doSomethingThatCanThrow();
// do something with result if didn't throw
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
}
Keep it mind that it can always grow.
Also I could always skip rethrowing but I want to add some more information to error.
Which option is better and why? Are there any other possibilities?

You can utilize finally
(async(doSomethingThatCanThrow) => {
let result;
try {
result = await doSomethingThatCanThrow();
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
} finally {
if (result !== undefined) {
// do something with result if didn't throw
console.log(result);
} else {
console.log(result);
}
}
// do stuff
})(() => Promise.reject(123))
.catch(err => console.error(err));

Try a test condition to see if the variable result is empty, or not!
var result
try {
result = "This time it worked!";
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
}
if (result) {
console.log(result)
}
var result
try {
} catch (e) {
}
// do something with result if didn't throw
if (!result) {
// var result undefined
// Result not thrown!
console.log("Failed")
}

In this case, I think the only real way to avoid let (other than using var as another response suggested - don't do that), is to extract this try-catch into a function and return the result directly with the try block, i.e.
const doSomethingThatCanThrowAndRethrowWithUpdatedMessageIfFails = () => {
try {
return doSomethingThatCanThrow();
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`);
}
}
const result = doSomethingThatCanThrowAndRethrowWithUpdatedMessageIfFails();

Related

What is the difference between throw Error(error) and throw error

What is the difference between:
try {
const result = await hello();
} catch (error) {
throw error;
}
and
try {
const result = await hello();
} catch (error) {
throw Error(error);
}
Also
Is the second one necessary? It seems like you are just wrapping an error with an Error Object. Which one is preferred? Please help me understand.
It's possible that the value that the Promise rejected with was not an error object, but something else:
(async() => {
try {
const result = await Promise.reject(5);
} catch (error) {
console.log(error);
console.log(typeof error);
}
})();
Doing
throw Error(error);
makes sure that the value being thrown is definitely an Error object, which could be important if the thrown value is examined later and is expected to be such an object. You wouldn't want, for example, for undefined or null to be thrown (strange, I know, but not impossible) and for accessing a property of that to then throw at the point where you're catching for real.
const hello = () => new Promise((resolve, reject) => {
reject();
});
(async() => {
try {
const result = await hello();
} catch (error) {
throw error;
}
})()
.catch((error) => {
console.log('The error message was:');
console.log(error.message);
});

NodeJS use errors for specific cases

Im using the following function that works ok, However I have some issue with the error handling
e.g.
I want to catch generic error for all the functions
If fn1 or fn2 returns any error the function should throw 'generic error occurred`
Here is the what I need
if getData2 doesn’t have specific property value (see the if) return a uniq error uniq error occurred and not the general error...
This is working example
https://jsfiddle.net/8duz7n23/
async function func1() {
try {
const data = await getData1()
console.log(data)
const data2 = await getData2();
if (!data2.url === !"https://test2.com") {
throw new Error("uniq error occurred ")
}
return data2.url
} catch (e) {
throw new Error("generic error occurred ")
}
}
async function getData1() {
return "something"
}
async function getData2() {
return {
url: "http://test.com"
}
}
func1().then(result => {
console.log(result);
}).catch(error => {
console.log(error);
});
Now If I throw the uniq error the catch will throw the general error.
I want that in case func2 will have some error it still throw away
a general error but just if doenst have the right url,
trow all the way up the uniq error ...
Is there any cleaner way to do it in nodejs?
I dont want to use an if statement for messages in the catch etc...
I want that the will thrown to the upper level function and not to the catch
In order to propagate error to the "upper level", you should have to throw it again in catch block.
You can add your custom error type and check if the error is what you're looking for or not.
class UrlMismatchError extends Error {
name="UrlMismatchError"
}
async function func1() {
try {
const data = await getData1()
console.log(data)
const data2 = await getData2();
if (data2.url !== "https://test2.com") {
throw new UrlMismatchError("uniq error occured");
}
return data2.url
} catch (e) {
if (e instanceof UrlMismatchError) {
throw e;
} else {
// handle generic errors
throw new Error("generic error occured");
}
}
}
async function getData1() {
return "something"
}
async function getData2() {
return {
url: "http://test.com"
}
}
func1().then(result => {
console.log(result);
}).catch(error => {
console.error(error.message);
});
I dont want to use an if statement for messages in the catch etc...
I want that the will thrown to the upper level function and not to the catch
No you cannot do that, because javascript is not java, so you cannot do such thing as the follows:
// the code snippet below wont work
try {
doSomething();
} catch(UrlMismatchError e) {
// propagate error to the upper level
throw e;
} catch(Error e) {
// handle all the other errors
console.log(e);
}

Why does Jest pass test if function is declared asynchronous?

This passes
test('test_test', async () => {
try {
const received = true;
const expected = false;
expect(received).toBe(expected);
} catch (err) {
return err
}
});
This fails as it should
test('test_test', () => {
try {
const received = true;
const expected = false;
expect(received).toBe(expected);
} catch (err) {
return err
}
});
I have a function using async and await and this is the reason the test will not fail so I'm trying to understand how to make the top fail as it should.
As #jonrsharpe suggested to remove try/catch it behaves as expected now and fails.

Confusion around 'nested' try/catch statements in Javascript

Essentially I have an async function containing a try/catch that calls another async function also containing a try catch, and I'm getting a bit confused about how to properly implement what I'm doing. Some "pseudocode" showing my current implementation:
const main = async () => {
try {
const test = await secondFunc();
console.log(test);
} catch(err) {
console.log('Found an error!');
console.log(err);
}
const secondFunc = async () => {
try {
await performSomeRequestExample();
} catch(err) {
if (err.x === 'x') {
doSomething();
} else {
//********
throw err;
//********
}
}
So what I'm trying to do is get the throw(err) (surrounded by the asterisks) to be caught by the catch in main() which will also call the console.log('Found an error!'), but what currently happens is the error is thrown from secondFunc(), the catch in main() is never hit and I get an unhandled promise rejection.
Any guidance on what I'm doing wrong?
My advice is to minimize using try/catch unless absolutely necessary. With async functions (or any functions that return a Promise object) you can usually simplify things by not worrying about try/catch blocks unless you need to do something specific with certain errors. You can also use .catch rather than try/catch blocks to make things easier to read.
For example your code above could be written like this:
const main = async () => {
const test = await secondFunc().catch(err => {
console.log("Found an error from secondFunc!", err);
throw err; // if you want to send it along to main's caller
});
if (test) {
console.log("Test", test);
}
};
const secondFunc = () => {
return performSomeRequestExample().catch(err => {
if (err.x === "x") {
doSomething();
} else {
throw err;
}
});
};
const performSomeRequestExample = () => Promise.reject("bad");
main().then(
() => console.log("worked"),
err => console.log("failed from main", err)
);
In secondFunc we don't need to use async since we can just return the promise coming back from performSomeRequestExample and handle any failures in the .catch.
You should use
const secondFunc = async () => {
performSomeRequestExample().then(res =>{
console.log(res);
})
.catch(err => {
console.log(err);
}
)
Add a return before the await of performSomeRequestExample.
const secondFunc = async () => {
try {
return await performSomeRequestExample();
} catch (err) {
if (err.x === 'x') {
console.log('x');
} else {
throw err;
}
}
}
or you can also use .catch() after the awaited function.
Another solution can be like this
const main = async() => {
try {
const test = await secondFunc();
console.log(test);
} catch(err) {
console.log('Found an error!');
console.log(err);
}
}
const secondFunc = async () => {
//return await performSomeRequestExample(); //for success
return await performSomeRequestExample(2); //for error
}
const performSomeRequestExample = async(abc=1) => {
return new Promise(function(resolve,reject){
if(abc ==1){
setInterval(resolve("yes"),400);
}else{
setInterval(reject("opps"),400);
}
});
}
main();
Test this code at this link:
https://repl.it/repls/JoyfulSomberTelevision

Throw custom errors async/await try-catch

Let's say I have a function like this -
doSomeOperation = async () => {
try {
let result = await DoSomething.mightCauseException();
if (result.invalidState) {
throw new Error("Invalid State error");
}
return result;
} catch (error) {
ExceptionLogger.log(error);
throw new Error("Error performing operation");
}
};
Here the DoSomething.mightCauseException is an asynchronous call that might cause an exception and I'm using try..catch to handle it. But then using the result obtained, I might decide that I need to tell the caller of doSomeOperation that the operation has failed with a certain reason.
In the above function, the Error I'm throwing is caught by the catch block and only a generic Error gets thrown back to the caller of doSomeOperation.
Caller of doSomeOperation might be doing something like this -
doSomeOperation()
.then((result) => console.log("Success"))
.catch((error) => console.log("Failed", error.message))
My custom error never gets here.
This pattern can be used when building Express apps. The route handler would call some function which might want to fail in different ways and let the client know why it failed.
I'm wondering how this can be done? Is there any other pattern to follow here? Thanks!
Just change the order of your lines.
doSomeOperation = async() => {
let result = false;
try {
result = await DoSomething.mightCauseException();
} catch (error) {
ExceptionLogger.log(error);
throw new Error("Error performing operation");
}
if (!result || result.invalidState) {
throw new Error("Invalid State error");
}
return result;
};
Update 1
Or you could create custom errors as below.
class MyError extends Error {
constructor(m) {
super(m);
}
}
function x() {
try {
throw new MyError("Wasted");
} catch (err) {
if (err instanceof MyError) {
throw err;
} else {
throw new Error("Bummer");
}
}
}
x();
Update 2
Mapping this to your case,
class MyError extends Error {
constructor(m) {
super(m);
}
}
doSomeOperation = async() => {
try {
let result = await mightCauseException();
if (result.invalidState) {
throw new MyError("Invalid State error");
}
return result;
} catch (error) {
if (error instanceof MyError) {
throw error;
}
throw new Error("Error performing operation");
}
};
async function mightCauseException() {
let random = Math.floor(Math.random() * 1000);
if (random % 3 === 0) {
return {
invalidState: true
}
} else if (random % 3 === 1) {
return {
invalidState: false
}
} else {
throw Error("Error from function");
}
}
doSomeOperation()
.then((result) => console.log("Success"))
.catch((error) => console.log("Failed", error.message))
You can simply use throw instead of using Error constructor
const doSomeOperation = async () => {
try {
throw {customError:"just throw only "}
} catch (error) {
console.log(error)
}
};
doSomeOperation()

Categories