The finally block is a part of a try…catch…finally statement, which allows you to handle errors and perform cleanup operations regardless of whether an exception is thrown or not. The finally block is executed regardless of whether an exception occurs or not, and it is placed after the try and catch blocks.
Having a jump statement, such as return, break, continue, or throw, inside a finally block can lead to unexpected and undesirable behavior, making your code difficult to understand and maintain. While it’s not inherently forbidden to use jump statements in finally blocks, it is generally discouraged for the following reasons:
finally block is to ensure cleanup operations and code that must run regardless of the outcome, such as releasing resources or closing connections. If you use a return statement inside the finally block, it will override any previous return statements in the try or catch blocks. This can lead to unexpected values being returned from a function.break, continue, or even another throw inside the finally block can alter the normal control flow of the program. This can make it difficult to reason about the behavior of the code and may introduce subtle bugs that are hard to detect.return or throw statement inside the finally block causes a new exception or alters the return value, it can hide or suppress the original exception or return value from the try or catch blocks. This can make it challenging to identify the actual cause of an error.finally blocks can be hard to read and understand, especially for other developers who might not be familiar with the unusual control flow. Such code can lead to maintenance issues and make it harder to debug and maintain the application in the long run.This rule reports on all usages of jump statements from a finally block. Even if it’s guaranteed that no unhandled exception can happen in try or catch blocks, it’s not recommended to use any jump statements inside the finally block to have the logic there limited to the "cleanup".
async function foo() {
let result, connection;
try {
connection = await connect();
result = connection.send(1);
} catch(err) {
console.error(err.message);
} finally {
if (connection) {
connection.close();
}
return result; // Noncompliant: Jump statement 'return' in the 'finally' block
}
}
While there might be rare cases where using jump statements in a finally block is necessary, it’s generally recommended to avoid it whenever possible. Instead, use the finally block only for cleanup operations and critical tasks that should always be executed, regardless of exceptions or return values.
async function foo() {
let result, connection;
try {
connection = await connect();
result = connection.send(1);
} catch(err) {
console.error(err.message);
} finally {
if (connection) {
connection.close();
}
}
return result;
}
No issue will be raised when a void return statement is used as a guard clause to conditionally skip cleanup operations in a finally block. The condition may be a simple boolean flag, a property access expression (including optional chaining), or a negated boolean expression.
async function fetchData() {
let cancelled = false;
try {
const response = await fetch('/api/data');
return response.json();
} finally {
if (cancelled) {
return; // Compliant by exception: simple flag guard clause
}
console.log('Cleanup operations');
}
}
async function closePopover() {
try {
await field.form.validate();
} finally {
const errors = field.form.queryFeedbacks({ type: 'error' });
if (errors?.length) {
return; // Compliant by exception: property access guard clause
}
setVisible(false);
}
}
async function fetchResource() {
let isActive = true;
try {
const data = await fetch('/api/data');
processData(data);
} finally {
if (!isActive) {
return; // Compliant by exception: negated boolean guard clause
}
setLoading(false);
}
}
finally blocktry...catchreturnthrowbreakcontinue