Don't let the Try Catch Tower of Terror destroy your beautiful one liners.
npm install @bdsqqq/try
import { trytm } from "@bdsqqq/try";
const mockPromise = () => {
return new Promise<string>((resolve, _) => {
setTimeout(() => {
resolve("hello from promise");
}, 1000);
});
};
const mockPromiseThatFails = () => {
return new Promise<string>((_, reject) => {
setTimeout(() => {
reject(new Error("hello from promise"));
}, 1000);
});
};
const [data, error] = await trytm(mockPromise());
const [data2, error2] = await trytm(mockPromiseThatFails());
Async await feels like heaven because it avoids the callback hell or Pyramid of Doom by writing asyncronous code in a line by line format:
function hell() {
step1((a) => {
step2((b) => {
step3((c) => {
// ...
})
})
})
}
async function heaven(){
const a = await step1();
const b = await step2(a);
const c = await step3(b);
// ...
}
Until error handling comes into play... Because then you end up with the Try-Catch Tower of Terror, where your beautiful one-liners magically expand to at least 5 lines of code:
async function Terror(){
let a;
let b;
let c;
try {
a = await step1();
} catch (error) {
handle(error);
}
try {
b = await step2(a);
} catch (error) {
handle(error);
}
try {
c = await step3(b);
} catch (error) {
handle(error);
}
// ...
}
An easy solution would be to append the .catch()
method to the end of each promise:
async function easy(){
const a = await step1().catch(err => handle(err));
const b = await step2(a).catch(err => handle(err));
const c = await step3(b).catch(err => handle(err));
// ...
}
This approach solves the issue but can get a bit repetitive, another approach is to create a function that implements one Try Catch to replace all the others:
import { trytm } from "@bdsqqq/try"
async function awesome() {
const [aData, aError] = await trytm(step1());
if(aError) // ...
const [bData, bError] = await trytm(step2(aData));
if(bError) // ...
const [cData, cError] = await trytm(step3(bData));
if(cError) // ...
// ...
}
I watched a fireship short and ended up in a rabbit hole to learn how to publish a NPM package. This is still an interesting pattern to use in your codebase but might be best copy pasted instead of being a dependency.
I'll leave the source code here so you don't have to look for the one .ts file in the /src folder:
export const trytm = async <T>(
promise: Promise<T>,
): Promise<[T, null] | [null, Error]> => {
try {
const data = await promise;
return [data, null];
} catch (throwable) {
if (throwable instanceof Error) return [null, throwable];
throw throwable;
}
};
This code is blatantly stolen from a fireship youtube short, with minor additions to make data
infer its typing from the promise passed as an argument.