New issue
Advanced search Search tips

Issue 775391 link

Starred by 1 user

Issue metadata

Status: Available
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Mac
Pri: 2
Type: Feature



Sign in to add a comment

history API is asynchronous, preventing: history.go(); history.replaceState(); from applying state to correct entry

Reported by jamesgil...@gmail.com, Oct 17 2017

Issue description

UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.0 Safari/537.36

Steps to reproduce the problem:
1. history.pushState({}, null, '/foo')
2. history.go(-1)
3. history.replaceState({}, null, '/bar')

What is the expected behavior?
The URL you end up on is the first entry of 2 in the history stack (as indicated by the availability of the forward button) and has the url /foo.

What went wrong?
replaceState operates on the 2nd entry, changing it from /foo to /bar, while going back the original URL.

Did this work before? N/A 

Does this work in other browsers? N/A

Chrome version: 63.0.3239.0  Channel: n/a
OS Version: OS X 10.11.6
Flash Version: 

In other browsers (tested on Safari + Firefox, OSX), these operations are executed synchronously, correctly applying replaceState to the first entry. 

ALSO NOTE: this is a contrived example. A better example might be just changing the state object in step 3, as a means to go somewhere else in the stack, while simultaneously changing its state.
 

Comment 1 Deleted

To test this, make sure to paste steps 2 and 3 in the console and execute them together. It works if there is a pause of what seems to be at least 17ms between the two (i.e. one animation frame). 

For example this works:

history.go(-1)

setTimeout(() => {
  history.replaceState({}, null, '/bar')
}, 17)

while this does not:

history.go(-1)
history.replaceState({}, null, '/bar') // incorrect entry has its state replaced

Comment 3 by woxxom@gmail.com, Oct 17 2017

Try disabling chrome://flags/#browser-side-navigation and see if it helps.


unfortunately it did not. 

Comment 5 by kochi@chromium.org, Oct 17 2017

Components: -Blink>DOM UI>Browser>Navigation Blink>HTML
Labels: Hotlist-Interop
Status: Available (was: Unconfirmed)
History API is in HTML spec, so moving DOM to HTML component.
Also adding UI>Browser>Navigation.

At a glance at spec
https://html.spec.whatwg.org/multipage/history.html#the-history-interface
there is no mention about how history.go() (or back/forward) can be
asynchronous or synchronous.

Anyhow this behavior differs from other browsers, marking as
Hotlist-Interop.

Comment 6 by tkent@chromium.org, Feb 13 2018

Components: -Blink>HTML Blink>Loader

Comment 7 by japhet@chromium.org, Feb 13 2018

Cc: japhet@chromium.org
Labels: -Type-Bug Type-Feature
The spec for history.go() uses the "traverse the history by a delta" algorithm: https://html.spec.whatwg.org/multipage/history.html#traverse-the-history-by-a-delta

Step 5 is to queue a task to perform the history traversal. That strongly implies that it's permissible for the navigation to be asynchronous, so from a narrow spec-correctness perspective, this is working as intended.

That said, there's almost certainly room to improve the spec for this API. Some ideas I've heard floated that might help:
* Have a history operation queue, so that all operations are guaranteed to execute in-order.
* Make all history operations (including pushState and replaceState) async, and have them return a promise.

Sign in to add a comment