-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Consider sequences of two operations from the set { cross-document navigation, same-document navigation, cross-document history traversal, same-document history traversal }, both requested synchronously. (Although all traversals and cross-document navs do not actually finish synchronously.) E.g.
// cross-document nav, cross-document nav
location.search = "?1";
location.search = "?2";
// Assume our history list looks like [?1, ?1#2]
// same-document traversal, cross-document nav
history.back();
location.href = "?3";What does the spec say should happen here? What do browsers do? I have written a bunch of web platform tests and found out the following things.
This is largely a superset of #6773 which has some previous discussion.
In what follows, XDN = cross-document navigation, XDT = cross-document traversal, and similarly for SDN and SDT. ✔ means "matches the spec", ? means "not yet tested"
| First operation | Second operation | Spec result | Firefox result | Chrome result | Safari result |
|---|---|---|---|---|---|
| XDN | XDN | Second nav cancels first nav | ✔ | ✔ | ✔ |
| XDN | XDT | Traversal cancels nav | ✔ | ✔ | ✔ |
| XDN | SDN | SDN happens synchronously first, then XDN | ✔ | ✔ | ✔ |
| XDN | SDT | Traversal cancels nav | Traversal ignored; nav wins | ✔ | Traversal ignored; nav wins |
| XDN | window.stop() | Nav is canceled | ✔ | ✔ | ✔ |
| XDT | XDN | XDT and XDN race | XDN gets ignored (even if the XDT is very slow) | XDN gets ignored (even if the XDT is very slow) | XDT gets ignored (even if the XDN is very slow) |
| XDT | XDT | Traversals queued, but what "back"/"forward" means is computed sync | Ignore second XDT | Coalesce into a single XDT (which could go nowhere or could go +/-2) | Ignore first XDT |
| XDT | SDN | SDN un-queues all traversals and proceeds | For fragment SDN: queue up traversal after SDN; for pushState SDN: XDT gets stopped | SDN is ignored, XDT succeeds | Queue up traversal after SDN |
| XDT | SDT | Traversals queued, but what "back"/"forward" means is computed sync | Ignore second SDT | Coalesce into a single XDT (going +/-2) | Somehow the outer page gets reloaded?? |
| XDT | window.stop() | Un-queue the traverals | stop() ignored | stop() ignored | stop() ignored |
| XDT | browser stop | Un-queue the traverals | ? | ✔ | ? |
| SDN | XDN | SDN completes sync, XDN then proceeds | ✔ | ✔ | ✔ |
| SDN | XDT | SDN completes sync, XDT then proceeds | ✔ | ✔ | Somehow the outer page gets reloaded?? |
| SDN | SDN | SDN completes sync, second SDN completes sync | ✔ | ✔ | ✔ |
| SDN | SDT | SDN completes sync, SDT then proceeds | ✔ | ✔ | ✔ |
| SDN | window.stop() | SDN completes sync, stop() is too late so does nothing | ✔ | ✔ | ✔ |
| SDN | browser stop | SDN completes sync, stop is too late so does nothing | ✔ | ✔ | ✔ |
| SDT | XDN | XDN can cancel SDT if the SDT takes too long; otherwise it happens after the SDT | ✔? SDT is too fast to be sure. | ✔? SDT is too fast to be sure. | ✔? SDT is too fast to be sure. |
| SDT | XDT | Traversals queued, but what "back"/"forward" means is computed sync | Traverals queued, e.g. hashchange then load | Traverals queued, e.g. hashchange then load | XDT is ignored |
| SDT | SDN | SDN un-queues all traversals and proceeds | For fragment SDN: queue up traversal after SDN; for pushState SDN: SDT gets stopped | SDN is happens, but then SDT goes back to the entry computed when the back() call was made | Queue up traversal after SDN |
| SDT | SDT | Traversals queued, but what "back"/"forward" means is computed sync | Traverals are queued up and happen in order | Second SDT is ignored | First SDT is ignored |
| SDT | window.stop() | Un-queue the traveral | stop() ignored | stop() ignored | stop() ignored |
| SDT | browser stop | Un-queue the traveral | ? (hard to test for humans) | ? (hard to test for humans; we may avoid showing the browser stop button entirely to avoid flicker) | ? (hard to test for humans) |
Presumably the next step, as with everything in the great history rewrite project, is for @jakearchibald to try to find a model that (a) makes some theoretical sense; (b) matches as many browsers in as many cases as we can.
Some tentative notes:
- Firefox not treating fragment SDNs the same as pushState() SDNs seems bad
- Nobody agrees with the spec's idea that
history.back()andhistory.forward()should compute their destination synchronously. - It is attractive to go for simple variants like "everything queues", or "everything cancels ongoing stuff", or "everything is ignored if there is ongoing stuff". But that doesn't seem to match any browsers so is probably too risky :(.
- What should history.back() do when sync navigations are involved? #6773 has notes about a model where SDTs and XDTs queue in separate queues that mostly matches Firefox, inspired by analyzing the SDT SDN case.
- window.stop() is easy enough to fix: window.stop() does not cancel traversal navigations, but the stop button does #6905
- WPTs for browser stop are not possible now but will be one day: Add
browsingContext.stopw3c/webdriver-bidi#122