Search code examples
javascripttry-catch-finallyfinally

JavaScript try catch finally block change precedence of errors


Sometimes I have a code in try-catch-finally block when finally branch does some cleanup code which may throw an Error. An error in the finally branch suppresses a possible error in the main branch. I want exactly the opposite: see an error from the main branch always and an error from the finally branch only when the main branch proceeds without an error. I have came up with solution:

let thrownError = false;
try {
    doMainCode();
} catch (err) {
    thrownError = true;
    throw err;
} finally {
    try {
        doCleanUpCode();
    } catch (err) {
        if (!thrownError)
            throw err;
        console.error("Suppressed finally error", err);
    }
}

Which is cumbersome. Is there any simpler way how to change error precedence in try-catch-finally block?


Solution

  • The usual approach I've seen here, for better or worse, is to just always suppress errors in the finally (dumping them to the console or a secondary logging stream or similar).

    For places you don't want to do that, you could use a utility function to wrap your code to make it less cumbersome:

    tryFinally(
        () => {
            // ...do main code...
        },
        () => {
            // ...do cleanup code...
        }
    );
    

    Yes, that does involve a layer of creating and calling functions where you didn't have one before, but modern JavaScript engines are very fast at that, it's not likely to cause a performance issue. (And if it does, you can address the specific places where it does.)

    The tryFinally utility function would be responsible for handling the error stuff. Here's a quick sketch of an implementation:

    function tryFinally(work, cleanup) {
        try {
            work();
        } catch (err) {
            try {
                cleanup();
            } catch (cleanupError) {
                console.error("Suppressed finally error", cleanupError);
            }
            throw err;
        }
        cleanup();
    }