Skip to content

Commit

Permalink
Explainer update to restrict canceling traversals to same-document only
Browse files Browse the repository at this point in the history
Closes #254. This is already reflected in the specification at whatwg/html#8502.
  • Loading branch information
natechapin authored Apr 12, 2023
1 parent 150c373 commit 4b4e33b
Showing 1 changed file with 3 additions and 3 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,14 +490,14 @@ Second, **traversals have special restrictions on canceling the navigation** via
Traversals may only be canceled (and `event.cancelable` will be equal to true) if:
- The navigate event is firing in the top window
- The traversal is same-origin
- The traversal is same-document
- The traversal was not user-initiated, or there is a consumable activation in the current window.
Allowing cancelation only in the top window is to ensure that there is a single authoritative source for deciding whether or not to cancel the traversal. If all windows were allowed to cancel and a traversal navigated multiple windows, and some canceled but others proceeded, there would not be a good way to keep all windows in sync with the joint session history. Cross-origin traversals are uncancelable in order to lessen the risk of trapping the user. Similarly, user activation is required for user-initiated traversals in order to minimize the possibility of trapping: `event.preventDefault()` on a traversal consumes the user activation, ensuring that the user can always break out of an application that is canceling traversals by, e.g., pressing the browser's back button twice in a row.
Allowing cancelation only in the top window is to ensure that there is a single authoritative source for deciding whether or not to cancel the traversal. If all windows were allowed to cancel and a traversal navigated multiple windows, and some canceled but others proceeded, there would not be a good way to keep all windows in sync with the joint session history. Cross-document traversals are uncancelable because of performance concerns. If a cross-document traversal were cancelable, it would need to block before any network requests are sent in order to fire `navigate`. This is already necessary for `beforeunload`, but `beforeunload` is a single-purpose event and if no `beforeunload` handler is present, the blocking step can be skipped. `navigate`, on the other hand, is intended to be used for many purposes, and it is wasteful to impose a performance penalty on all cross-document traversals simply because `navigate` was being used for something unrelated to canceling cross-document navigations. Finally, user activation is required for user-initiated traversals in order to minimize the possibility of trapping: `event.preventDefault()` on a traversal consumes the user activation, ensuring that the user can always break out of an application that is canceling traversals by, e.g., pressing the browser's back button twice in a row.
By _consumable activation_, we mean a variant of [user activation](https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation) that we wish to add to the HTML spec. _Sticky activation_ is obviously not correct for preventing trapping the user, because then a single errant click or tap could disable back/forward navigations entirely. However, we are also concerned about using _transient activation_: it meets our requirement that the user activation can be used once before it is consumed, but the possibility of it expiring due to its _transient activation duration_ elapsing means that web applications may suddenly and unexpectedly get an uncancelable traversal if a back or forward button is pressed and the user happens not to have interacted with the page for a modest period of time. We therefore intend to add a third mode of user activation to the HTML spec, _consumable activation_, which can be consumed like _transient activation_, but does not expire based on the _transient activation duration_.
In order to enable cancelation, traversals need to fire the `navigate` event at a precise time. Most navigations fire `navigate` at the time of navigation start, but that is not a viable time for traversals, because browser architecture may require an async step to determine which frames must navigate as part of the traversal (and therefore which frames need a `navigate` event). Alternately, we could fire at `unload` time, but that is very late: by then, network requests have already been performed. `beforeunload` time splits the difference: after determining which frames will be navigated, but before any network requests or other side effects have happened. The downside of this timing is that it builds on the rickety foundation of `beforeunload` (which is widely considered to be a regrettable web platform feature). However, we are avoiding the most problematic part of `beforeunload`, which is the modal user-facing dialog it creates. Simply reusing the internal browser and spec architecture for firing `navigate` at the same time as `beforeunload` is more benign.
Because canceling is limited to same-document traversals, no special timing or handler is required for firing `navigate`; the standard fragment navigation timing just works. If the performance concerns around canceling cross-document traversals were to be resolved at some point in the future, special consideration would need to be given to firing `navigate` at the correct time in the traversal process (presumably at the same time that `beforeunload` is fired).
Finally, the following navigations **cannot be replaced with same-document navigations** by using `event.intercept()`, and as such will have `event.canIntercept` equal to false:
Expand Down

0 comments on commit 4b4e33b

Please sign in to comment.