TaskWrite withSpinner(work) that logs 'spinner on', calls work() in try/catch/finally, logs 'caught: ' + err.message if it throws, and logs 'spinner off' in finally — re-throw the error after. Call it with work = () => { throw new Error('boom') } inside an outer try/catch; outer catch logs 'outer: ' + err.message.
try / catch / finally
100 XP7 min
Theory
finally runs always
finally runs whether or not the try threw — even if the catch threw, even if a return happened. It's the only safe place for cleanup that MUST happen.
function withConnection(work) {
const conn = openConnection();
try {
return work(conn);
} catch (err) {
console.error("work failed:", err);
throw err;
} finally {
conn.close(); // ALWAYS runs
}
}Common shape
The "wrap a risky thing, always tear it down" pattern:
- Open a file → finally close it.
- Start a transaction → finally rollback if not committed.
- Show a spinner → finally hide it.
Re-throwing
throw err inside a catch re-throws the same error. The finally still runs first; then the throw propagates to the caller. The original stack is preserved.
return inside finally is a trap
return inside finally overrides any return from try/catch and silently swallows pending throws. Always use finally for SIDE EFFECTS, never for return values.
🔒
Sign up to start coding
Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial — card required, cancel anytime.
Sign up — free trial →First 10 lessons in each track are free. No card needed for those.