-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
popstate/hashchange dispatching doesn't match what browsers do. #1792
Comments
@annevk I'm willing to push this forward. I found that Webkit raises compatibility concerns and decided not to implement popstate async: Chrome seems to keep the same behavior as Webkit at this part - sync popstate & async hashchange: Could you loop some people from webkit / chrome / edge to see if they have some comments? I think if major browsers are all behave the same, we should update the spec accordingly. |
The proposal is to align popstate/hashchange with Chrome and Safari and fire the first directly and the second from a task. Anyone any comments on that? |
@tkent-google, can you figure out who the Blink contact for this would be? |
I don't think so. Maybe japhet@chromium or kinuko@chromium knows it. |
@kinu, do you know? (I can't find japhet on GitHub.) |
@natechapin you probably know more about this? |
Fun fact: Chrome does not synchronously fire popstate for fragment navigations. It waits until "document close", i.e. Combined with the fact that we queue hashchange events (per the original post in this issue), this bit us recently in https://bugs.chromium.org/p/chromium/issues/detail?id=1254926. The basic situation is <!doctype html>
<script>
window.onload = () => console.log("load");
window.onpopstate = () => console.log("popstate");
window.onhashchange = () => console.log("hashchange");
location.hash = "#1";
</script> Chrome is trying to introduce a HTML parser that yields to the event loop more often before the
I'm not sure what the right solution is here, but I don't like how this sort of stuff makes the yield points observable. I suspect the blame lies with queuing hashchange since that makes it run at the next yield point. Maybe we can hold both hashchange and popstate until the load event, and either queue or synchronously fire hashchange then. |
I have written some tests at web-platform-tests/wpt#32392. I have not yet found a Safari computer to run them against. The problem cases really seem to be about changing Notably Chrome's behavior differs between Canary and stable. And per the above it might depend on parser yield points and thus not be deterministic. I think this gives us more freedom to match Firefox-like behavior. However I think Firefox might still do task-queuing, which I worry about because it could cause the non-determinism Chrome is currently exhibiting. So this might be one proposal:
I will investigate Safari behavior next week and see if this plan might work out. A less-ambituous plan is to avoid the queue of hash changes and allow that level of parser-based nondeterminism. That would still preserve the popstate-then-hashchange order, as well as the every-change-generates-both-events invariant. It would mean hashchange could be either before or after the load event though. I do worry that firing popstate sync (even if the change happens before load) might be a compat risk for Chrome. So if @smaug---- can confirm that Firefox in all fragment navigation cases fires popstate sync, and that this hasn't been a source of compat bugs, that would help alleviate my concerns. |
Firefox queues hashchange, but not popstate, as mentioned initially What causes Chrome fires popstate after load? Does it happen always or only if .hash was modified just before load? I don't understand what "separate queue". One just queues a task to fire hashchange. And yes, in FF, location.hash is synchronous, so popstate is sync. |
@natechapin and I are planning to try aligning Blink and the spec with Gecko here. Since you have not experienced any compat issues we are encouraged that we try that without compat problems. @natechapin's analysis of the compat risks for Blink changing this are that it reduces to the following scenarios:
Both of these are not too risky because (a) Firefox has gotten away with it for many years without problems; (b) ordering is already unreliable and has even changed recently in Chromium. I will work on a spec PR now where we can see in more detail. And @natechapin and I will collaborate on web platform tests. Now for a history lesson!! Why is Chromium delaying popstate until after load? Well, apparently the spec used to ask us to do so! See this old working draft. This changed in 4e57ced#diff-42692259bbea922a55e8e0f8a8b7860df9b59e29b3f955bcfd4d0a3ca852cc01L60686 , as a result of discussions in https://www.w3.org/Bugs/Public/show_bug.cgi?id=11468 and https://www.w3.org/Bugs/Public/show_bug.cgi?id=12277 . The change in turn is based on something Firefox very intentionally led the way on, and even blogged about: https://hacks.mozilla.org/2011/03/history-api-changes-in-firefox-4/ . As far as we can tell, other browsers implemented items 1 and 2 in that blog post, but not 3. And the spec got updated in a weird way that didn't really match any browser. |
Closes #1792 by aligning with Gecko. The alternative model involved delaying popstate until after the load event, which is what WebKit and Blink do. But the Gecko model is simpler and has fewer edge cases around multiple state changes and such.
There's definitely a pile of "back button works in Chrome but not Firefox" bugs out there though, see https://bugzilla.mozilla.org/show_bug.cgi?id=1643554 and https://github.com/webcompat/web-bugs/search?q=%22back+button%22+return&type=issues (maybe under-reporting, but https://github.com/webcompat/web-bugs/search?q=%22back+button%22&type=issues is over-reporting). cc @wisniewskit, who has diagnosed many of these bugs. |
I don't think any of those are related to popstate/hashchange ordering, though. Instead I believe most are due to inconsistent mapping of the back button to the joint session history, per WICG/interventions#21. |
Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9
Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3580022 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/main@{#996748}
Closes #1792 by aligning with Gecko. The alternative model involved delaying popstate until after the load event, which is what WebKit and Blink do. But the Gecko model is simpler, more deterministic (since the load event depends on network timing), and has fewer edge cases around multiple consecutive state changes.
Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3580022 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/main@{#996748}
Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3580022 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/main@{#996748}
Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3580022 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/main@{#996748}
… a=testonly Automatic update from web-platform-tests Make popstate always fire synchronously Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3580022 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/main@{#996748} -- wpt-commits: 681dc9c986220956b3ffd0936963211603a0ba06 wpt-pr: 33746
… a=testonly Automatic update from web-platform-tests Make popstate always fire synchronously Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3580022 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/main@{#996748} -- wpt-commits: 681dc9c986220956b3ffd0936963211603a0ba06 wpt-pr: 33746
Closes whatwg#1792 by aligning with Gecko. The alternative model involved delaying popstate until after the load event, which is what WebKit and Blink do. But the Gecko model is simpler, more deterministic (since the load event depends on network timing), and has fewer edge cases around multiple consecutive state changes.
https://bugs.webkit.org/show_bug.cgi?id=245153 Reviewed by Brent Fulgham. PopState event should be fired synchronously, even before the load event: - whatwg/html#1792 We used to delay PopState events until the load event has fired but this doesn't match other Blink or Gecko. * LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/history-traversal/event-order/pushState-inside-popstate-expected.txt: Rebaseline WPT tests that are now passing or failing a little further. The ones that are still failing and due to the fact that we fire the load event synchronously instead of queuing a task. As a result, it may fire before hashchange events that were scheduled before the load has completed. I plan to look into this in a follow-up. * Source/WebCore/dom/Document.cpp: (WebCore::Document::implicitClose): (WebCore::Document::statePopped): * Source/WebCore/dom/Document.h: Canonical link: https://commits.webkit.org/254519@main
…n before the load event https://bugs.webkit.org/show_bug.cgi?id=245153 Reviewed by Brent Fulgham. PopState event should be fired synchronously, even before the load event: - whatwg/html#1792 We used to delay PopState events until the load event has fired but this doesn't match other Blink or Gecko. * LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/history-traversal/event-order/before-load-hash-twice-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/html/browsers/browsing-the-web/history-traversal/event-order/pushState-inside-popstate-expected.txt: Rebaseline WPT tests that are now passing or failing a little further. The ones that are still failing and due to the fact that we fire the load event synchronously instead of queuing a task. As a result, it may fire before hashchange events that were scheduled before the load has completed. I plan to look into this in a follow-up. * Source/WebCore/dom/Document.cpp: (WebCore::Document::implicitClose): (WebCore::Document::statePopped): * Source/WebCore/dom/Document.h: Canonical link: https://commits.webkit.org/254519@main (cherry picked from commit 9497f1b)
Interop discussion: whatwg/html#1792 Intent to ship: https://groups.google.com/a/chromium.org/g/blink-dev/c/HXRHWirKarU Bug: 1254926 Change-Id: I7e41ab603a15a14bf9df5000edca2724766a20e9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3580022 Reviewed-by: Domenic Denicola <domenic@chromium.org> Commit-Queue: Nate Chapin <japhet@chromium.org> Cr-Commit-Position: refs/heads/main@{#996748} NOKEYCHECK=True GitOrigin-RevId: 425a4f723fdc2b4118713b0aed8203621129f01a
When doing fragment navigation Gecko and Blink dispatch popstate sync but hashchange async. Per current spec both events should fire async using same task.
The text was updated successfully, but these errors were encountered: