olivercollins-inhome
olivercollins-inhome

Reputation: 25

What is the proper way to handle errors in a promise?

I've been seeing a couple of different patterns for handling errors.

One is like:

let result;

try {
    result = await forSomeResult(param);
} catch {
    throw new Error();
}

And the other is like:

const result = await forSomeResult(param).catch(() => throw new Error());

I prefer the latter since it looks like a cleaner solution. But I've also heard talks that the first solution is better since there could be some race condition where the .catch doesn't execute before the next command is run.

I was wondering if someone had a technical answer about why one method is better than the other.

Upvotes: 0

Views: 59

Answers (2)

jfriend00
jfriend00

Reputation: 708156

First of all, there's no reason to catch and throw or .catch() and throw unless you're going to do something else inside the catch handler or throw a different error. If you just want the same error thrown and aren't doing anything else, then you can just skip the catch or .catch() and let the original promise rejection go back to the caller.

Then, it is generally not recommended that you mix await with .catch() as the code is not as easy to follow. If you want to catch an exception from await, use try/catch around it. .catch() works, it's just not a preferred style if you're already awaiting the promise.

The one technical difference between these two styles:

async function someFunc()
     let x = await fn().catch(err => {
         console.log(err); 
         throw err;
     });
     // do something else with x
     return something;
}

And, this:

async function someFunc()
     let x;
     try {
         x = await fn();
     } catch(err) {
         console.log(err);
         throw err;
     }
     // do something else with x
     return something;
}

is if the function fn() you are calling throws synchronously (which it shouldn't by design, but could by accident), then the try/catch option will catch that synchronous exception too, but the .catch() will not. Because it's in an async function, the async function will catch the synchronous exception and turn it into a rejected promise for you automatically for the caller to see as a rejected promise, but it wouldn't get logged or handled in your .catch() handler.


One of the more beneficial cases for try/catch with await is when you have multiple await statements and you don't need to handle errors on any of them individually. Then, you can surround them with one try/catch and catch all the errors in one place.

async function someFunc(someFile) {
    let fileHandle;
    try {
        // three await statements in a row, all using same try/catch
        fileHandle = await fsp.open(someFile);
        let data = await fsp.read(...);
        // modify data
        await fsp.write(...)
    } catch(err) {
        // just log and re-throw
        console.log(err);
        throw err;
    } finally {
        // close file handle
        if (fileHandle) {
             await fileHandle.close();
        }
    }
}

Upvotes: 2

Klaycon
Klaycon

Reputation: 11090

It depends.

Are you going to be calling multiple asynchronous functions that could error? You can wrap them all in a try/catch and perform common error handling without having to repeat yourself:

try {
    result = await forSomeResult(param);
    await forSomeOtherResult();
    return await finalResult(result);
} catch { //catches all three at once!
    throw new Error();
}

Do you only need to handle errors for this one, specific call? The .catch() pattern is fine. There is no race condition to worry about, await waits for the promise to resolve or reject, and this includes all success and failure callbacks attached to the promise. However, in your example, you're catching an error only to throw an empty one - in that case, it may be preferable to simply write this:

const result = await forSomeResult(param);

...and let the error propagate to the caller naturally.

I've seen a mixture of both styles used common enough that I think it's fine either way - they each have a particular strength.

Upvotes: 0

Related Questions