The finally Block
The finally block runs after try and catch, whether an error happened or not.
try {
console.log("Trying");
} catch (error) {
console.log("Caught");
} finally {
console.log("Finished");
}Output:
Trying
Finishedfinally is useful for cleanup.
Basic Syntax
try {
// risky code
} catch (error) {
// handle error
} finally {
// always runs
}Example with an error:
try {
JSON.parse("{ bad json }");
} catch (error) {
console.log("Invalid JSON");
} finally {
console.log("Parse attempt finished");
}Output:
Invalid JSON
Parse attempt finishedfinally Runs on Success
try {
const user = JSON.parse('{"name":"Alice"}');
console.log(user.name);
} catch (error) {
console.log("Invalid JSON");
} finally {
console.log("Done");
}Output:
Alice
DoneEven though no error occurred, finally still runs.
finally Runs on Failure
try {
JSON.parse("{ bad json }");
console.log("Success");
} catch (error) {
console.log("Failure");
} finally {
console.log("Done");
}Output:
Failure
Donefinally Runs Before Control Leaves
finally runs even when the try or catch block returns.
function parseUser(json) {
try {
return JSON.parse(json);
} catch (error) {
return null;
} finally {
console.log("parseUser finished");
}
}
parseUser('{"name":"Alice"}');Output:
parseUser finishedThe function returns, but finally runs first.
Cleanup Use Cases
Use finally for cleanup work that should happen no matter what.
Examples:
- stop a loading spinner
- close a file or connection
- release a lock
- reset temporary state
- log that an operation completed
Example:
let isLoading = true;
try {
const data = JSON.parse(responseText);
console.log(data);
} catch (error) {
console.log("Could not parse response");
} finally {
isLoading = false;
}Whether parsing succeeds or fails, loading ends.
try...finally Without catch
You can use try...finally without catch.
function runTask() {
try {
console.log("Running task");
throw new Error("Task failed");
} finally {
console.log("Cleaning up");
}
}The error is not handled.
It still continues upward after finally runs.
This is useful when the current function cannot handle the error but must clean up.
Be Careful Returning From finally
Returning from finally can override returns from try or catch.
function example() {
try {
return "try";
} finally {
return "finally";
}
}
console.log(example()); // finallyThis is usually confusing.
Avoid return inside finally.
Be Careful Throwing From finally
Throwing from finally can hide the original error.
try {
throw new Error("Original error");
} finally {
throw new Error("Finally error");
}The finally error replaces the original one.
This can make debugging harder.
Keep finally blocks simple and safe.
Best Practices
Use finally for cleanup.
Keep finally short.
Avoid returning from finally.
Avoid throwing from finally unless absolutely necessary.
Use finally to reset state that must be reset on success or failure.
Common Mistakes
Mistake 1: Thinking finally Runs Only on Errors
finally runs on success and failure.
try {
console.log("Success");
} finally {
console.log("Always");
}Mistake 2: Returning From finally
function getValue() {
try {
return "try";
} finally {
return "finally";
}
}This returns "finally", which can surprise readers.
Mistake 3: Putting Error Handling Only in finally
finally is for cleanup, not normal error handling.
Use catch to handle errors.
Quick Check
What does this log?
try {
console.log("A");
throw new Error("Failed");
} catch (error) {
console.log("B");
} finally {
console.log("C");
}It logs:
A
B
CSummary
finally runs after try and catch.
- It runs whether an error happens or not.
- It is useful for cleanup.
- It runs before control leaves the block.
try...finallycan be used withoutcatch.- Avoid returning from
finally. - Avoid throwing from
finallyunless needed.