If you write apps using Node.JS, you've probably ended up in then-catch hell.
This code below works, but when you have to do large operations that require you to chain many promises together, it can get super repetitive and hard to read and maintain.
//then-catch hell
somePromise(arg1, arg2, arg3)
.then((result) => {
anotherPromise(arg1, arg2, arg3)
.then((anotherResult) => {
andAnotherPromise(arg1, arg2, arg3)
.then((andAnotherResult) => {})
.catch((error) => {
console.error(error);
});
})
.catch((error) => {
console.error(error);
});
})
.catch((error) => {
console.error(error);
});
This is where async/await can come in handy, but if you've ever used the await keyword on a promise, you probably needed to catch errors and ended up with some ugly code like this.
//try-catch tower of terror
let result;
try {
result = await somePromise(arg1, arg2, arg3);
} catch (error) {
return console.error(error);
}
let anotherResult;
try {
anotherResult = await anotherPromise(arg1, arg2, arg3);
} catch (error) {
return console.error(error);
}
Of course, you could always wrap all your operations in a single try-catch (example below), but you would lose granularity unless you are using your own libraries and writing unique error codes for everything that could go wrong (not fun). The lack of granularity in the example below would make it very hard to debug if something goes wrong.
try {
let result = await somePromise(arg1, arg2, arg3);
let anotherResult = await anotherPromise(arg1, arg2, arg3);
} catch (error) {
return console.error(error);
}
Now, I present to you no-try-catch! The solution to the hell you have been going through.
All you need to do is wrap your promises and check if the result has an error property. It also supports TypeScript, so the data property will be typed with the promise result.
import wrapper from "no-try-catch";
//or const wrapper = require("no-try-catch");
let result = wrapper(somePromise, [arg1, arg2, arg3]); //returns {error: Error, data: null} or {error: null, data: RESULT_FROM_PROMISE}
if (result.error) return console.error(result.error);
console.log(result.data);
You can install the package from NPM or review the source code on Github.
https://www.npmjs.com/package/no-try-catch
https://github.com/grangus/no-try-catch
If you find any bugs (you probably will), please open an issue on Github.
Top comments (2)
Never would have thought of that TBH. I really like the secure promise wrapper idea. I did originally plan on using a tuple instead of an object, but TypeScript loved to scream "data is possibly undefined or null". My solution ended up using an object instead. Thanks for the enlightenment. I'll be sure to hit you up with more programming questions in the future 🤠
This is nice, but the issue I see is with error granularity.
AFAIK this doesn't specify where the error came from. So, if you get one of those super generic errors for some reason, pinpointing which promise threw the error in the first place would be significantly harder.
Say you are calling an async function from some external library. Something happens and the lib throws an error like
Cannot read property "x" of undefined"
. You know the error originated from one of those chained promises, but you don't know which one threw the error.