Skip to content

rewrite finally section#43152

Merged
Josh-Cena merged 6 commits intomdn:mainfrom
s-egea:main
Mar 9, 2026
Merged

rewrite finally section#43152
Josh-Cena merged 6 commits intomdn:mainfrom
s-egea:main

Conversation

@s-egea
Copy link
Contributor

@s-egea s-egea commented Feb 17, 2026

Description

Re-write The finally block section in the try...catch statement documentation file trying to clarify control flow statements execution order while also keeping original structure and examples.

Motivation

The main point to clarify is the combination of the 3rd bullet points and the following sentence:

  • "Immediately before the execution of a control-flow statement (return, throw, break, continue) in the try block or catch block that would exit the block."
  • "If an exception is thrown from the try block, even when there's no catch block to handle the exception, the finally block still executes, in which case the exception is still thrown immediately after the finally block finishes executing."

The first part says that the finally block is entered before the execution of the control flow statement that would exit the try or catch block. The second implies that the finally block still executes after an exception is thrown (or the execution of a throw statement).

The proposed re-writing try to fix this inconsistency by adopting a point of view in which:

  • The finally block is always entered after the control flow statement that would exit the try or catch block
  • The effect of this control flow statement is deferred at the end of the finally block unless the finally block also ends with a control flow statement.

Additional details

Related issues and pull requests

Fixes #43122

@s-egea s-egea requested a review from a team as a code owner February 17, 2026 14:44
@s-egea s-egea requested review from wbamberg and removed request for a team February 17, 2026 14:44
@github-actions github-actions bot added Content:JS JavaScript docs size/m [PR only] 51-500 LoC changed labels Feb 17, 2026
@wbamberg wbamberg removed their request for review February 17, 2026 20:10
Copy link
Member

@Josh-Cena Josh-Cena left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I like this. Just some suggestions to make things more explicit.

- Immediately after the `try` block finishes execution normally (and no exceptions were thrown);
- Immediately after the `catch` block finishes execution normally;
- Immediately before the execution of a control-flow statement (`return`, `throw`, `break`, `continue`) in the `try` block or `catch` block that would exit the block.
- Immediately after the control flow exits the `try` block in a `try...finally` construct (e.g., after the last statement or a `throw` or `return` statement);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Immediately after the control flow exits the `try` block in a `try...finally` construct (e.g., after the last statement or a `throw` or `return` statement);
- Immediately after the control flow exits the `try` block in a `try...finally` construct (e.g., after the last statement or a `throw`, `return`, `break`, or `continue` statement);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

- Immediately before the execution of a control-flow statement (`return`, `throw`, `break`, `continue`) in the `try` block or `catch` block that would exit the block.
- Immediately after the control flow exits the `try` block in a `try...finally` construct (e.g., after the last statement or a `throw` or `return` statement);
- Immediately after the control flow exits the `catch` block in a `try...catch...finally` construct;
- Immediately after the control flow exits the `try` block in a `try...catch...finally` construct, unless it exits via a `throw` statement (in which case control flow enters the `catch` block first);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Immediately after the control flow exits the `try` block in a `try...catch...finally` construct, unless it exits via a `throw` statement (in which case control flow enters the `catch` block first);
- Immediately after the control flow exits the `try` block in a `try...catch...finally` construct, unless it exits via a `throw` statement (in which case control flow enters the `catch` block first).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

- Immediately after the control flow exits the `try` block in a `try...catch...finally` construct, unless it exits via a `throw` statement (in which case control flow enters the `catch` block first);

If an exception is thrown from the `try` block, even when there's no `catch` block to handle the exception, the `finally` block still executes, in which case the exception is still thrown immediately after the `finally` block finishes executing.
In most cases, if the `finally` block is entered after a control flow statement (`return`, `throw`, `break`, `continue`), the effect of this statement is deferred until after the last statement executed in the `finally` block. However, if the last statement executed in the `finally` block is itself a control flow statement, that statement will override the effect of the previous one (no deferral).
Copy link
Member

@Josh-Cena Josh-Cena Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In most cases, if the `finally` block is entered after a control flow statement (`return`, `throw`, `break`, `continue`), the effect of this statement is deferred until after the last statement executed in the `finally` block. However, if the last statement executed in the `finally` block is itself a control flow statement, that statement will override the effect of the previous one (no deferral).
If the `finally` block is entered after a control flow statement (`return`, `throw`, `break`, `continue`), the effect of this statement is deferred until after the last statement executed in the `finally` block. For example, if an exception is thrown from the `try` block, even when there's no `catch` block to handle the exception, the `finally` block still executes, in which case the exception is still thrown immediately after the `finally` block finishes executing and no other control flow statements were encountered.
However, if the last statement executed in the `finally` block is itself a control flow statement, that statement will override the effect of the previous one (no deferral).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the canonical example with a few changes

  • removed "and no other control flow statements were encountered" as I find it difficult to understand this before the general rule has been described (case where the finally ends with a control flow statement)
  • changed "in which case the exception is still thrown" to "and the exception is thrown"

```

Control flow statements (`return`, `throw`, `break`, `continue`) in the `finally` block will "mask" any completion value of the `try` block or `catch` block. In this example, the `try` block tries to return 1, but before returning, the control flow is yielded to the `finally` block first, so the `finally` block's return value is returned instead.
In the same way, any `return` statement in the `try` block is deferred at the end of the `finally` block.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In the same way, any `return` statement in the `try` block is deferred at the end of the `finally` block.
In the same way, any `return` statement in the `try` block is deferred at the end of the `finally` block, although the return value expression is evaluated before entering the `finally` block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied. Also used "the effect of any return statement" for consistent terminology

}
```

It is generally a bad idea to use control flow statements (`return`, `throw`, `break`, `continue`) in the `finally` block, as it makes the code harder to read. Most of the time, the `finally` block should be reserved for cleanup code.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
It is generally a bad idea to use control flow statements (`return`, `throw`, `break`, `continue`) in the `finally` block, as it makes the code harder to read. Most of the time, the `finally` block should be reserved for cleanup code.
It is generally a bad idea to use control flow statements (`return`, `throw`, `break`, `continue`) in the `finally` block, because they will "mask" the original control flow effect, which is rarely intended. Most of the time, the `finally` block should be reserved for cleanup code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied.

  • Kept "which is rarely intended"
  • Changed "mask" to "override" for consistent terminology
  • Used "the effect of any previously executed control flow statement" for consistent terminology


The following examples illustrate this.

If control flow reaches two `return` statements (possibly in the `try` and `finally` blocks or in the `catch` and `finally` blocks), both statements are executed in the correct order (which matters in the case of side effects). Only the function's returned value will be the one associated with the last `return` statement executed (which is the one in the `finally` block).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If control flow reaches two `return` statements (possibly in the `try` and `finally` blocks or in the `catch` and `finally` blocks), both statements are executed in the correct order (which matters in the case of side effects). Only the function's returned value will be the one associated with the last `return` statement executed (which is the one in the `finally` block).
If control flow exits the `try` or `catch` block via a `return` statement, the return value is evaluated (`order.sort()` in the example below). However, the `return` _statement_'s execution is deferred until the `finally` block finishes executing. Because the `finally` block also executes a `return` statement, the latter statement causes the first `return` to never execute.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied

  • Kept the idea of describing the example in more detail
  • Introduced "the function is planned to return..." terminology

s-egea added 2 commits March 2, 2026 14:02
- some control flow statements are not affected by the `finally` block (e.g. a `continue` inside and not exiting the `try` block)
@s-egea
Copy link
Contributor Author

s-egea commented Mar 2, 2026

@Josh-Cena as far as I am concerned, the PR is ready for a 2nd review. I tried to keep the core ideas behind your suggestions while also maintaining wording consistency.

Copy link
Member

@Josh-Cena Josh-Cena left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thank you! Now that the examples are more significant and self-contained, I moved them into the "Examples" section, which makes the description look leaner.

@Josh-Cena Josh-Cena merged commit 203acfa into mdn:main Mar 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Content:JS JavaScript docs size/m [PR only] 51-500 LoC changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clarify execution order of control flow statements with finally

2 participants