[whatwg] pushState and session history issues

Ian Hickson ian at hixie.ch
Thu Aug 12 16:56:58 PDT 2010

On Mon, 7 Jun 2010, Mike Wilson wrote:
> Ian Hickson wrote:
> > Mike Wilson wrote:
> > > the semantic contract is coming closer and closer to that of the 
> > > other storage APIs, so I think it would be an advantage to use the 
> > > same interface as well.
> > 
> > I don't see the relevance of storage APIs here. This isn't a storage 
> > model. It's more a callback model.
> I disagree. Once an API persists state between page loads it deserves to 
> be regarded as a storage API and not just a callback API. The data 
> objects supplied in pushState calls may be persisted for the lifetime of 
> their browsing context (unless history entry is removed), just like data 
> in session storage.

I'm not really convinced that this makes it a storage API, nor am I 
convinced that we should make all the storage mechanisms have the same 
API, even if it did.

> There should be good reasons why not to reuse existing API patterns.
> Why is "pushState" inventing a new API pattern where a copy of the state 
> is forwarded through new methods and events, instead of accessing it 
> through a storage facade (see sessionStorage and localStorage) as in 
> WebStorage?

Well, it was defined first, to start with. :-)

> Why is "pushState" defining a more restrictive model to state access 
> (read once / write anytime) compared to WebStorage (read anytime / write 
> anytime) ?
> What use-cases are solvable in the current "pushState" model but not in 
> a WebStorage-style model? (see below for WebStorage-style example)

There are often many ways to solve these kinds of problems. When 
pushState() was designed, it was envisioned as a mechanism to annotate the 
session history, which is why it ended up being the way it is.

> Ian Hickson wrote:
> > Mike Wilson wrote:
> > > Why not use the same API as in Web Storage:
> > >   interface Storage {
> > >     readonly attribute unsigned long length;
> > >     getter DOMString key(in unsigned long index);
> > >     getter any getItem(in DOMString key);
> > >     setter creator void setItem(in DOMString key, in any data);
> > >     deleter void removeItem(in DOMString key);
> > >     void clear();
> > >   };
> > > and make the current entry's Storage instance always available
> > > as f ex:
> > >   interface History {
> > >     readonly attribute Storage state;
> > >   }
> > > 
> > > Then pushState's state parameter may be removed and there is
> > > no longer a need for the replaceState method.
> > 
> > I don't understand how this would work. When does the history 
> > get updated in this model?
> The pushState method (without state parameter and possibly 
> renamed) remains to create a new session history entry:
>   function() {
>     history.state.setItem("a", 1); // set on current history entry
>     history.pushState(title, url); // create new history entry
>     history.state.getItem("a"); // get from new history entry (null)
>     history.state.setItem("a", 2); // set on new history entry
>   }
> > How do you know you've gone back in history? 
> The popstate event (without state attribute) remains to inform 
> us that history entry has been switched and that the corresponding
> data is now available through history.state.

Yeah, we could have done it that way. I don't know that it's better or 
worse, personally.

On Wed, 23 Jun 2010, Justin Lebar wrote:
> Safari 5 and Chrome 5 recently shipped the history.pushState and 
> replaceState methods.  Firefox 4 will also include those methods when it 
> ships.
> pushState and replaceState take three arguments: An opaque data object, 
> a title, and an optional URL.  Currently, Safari and Chrome both ignore 
> the title parameter.
> Jonas Sicking <jonas at sicking.cc> and I have been talking with Brady 
> Eidson <beidson at apple.com> and Darin Fisher <darin at chromium.org>, about 
> what we can do to clean up this API, since having an unused parameter in 
> our brand-new functions is unfortunate.
> Ideally, we might change the pushState and replaceState methods 
> themselves, perhaps changing them so they only take a URL and an 
> optional data object.  But since Chrome and Safari have already shipped 
> the method, and since we hear that the functions are already being used 
> on the web, it's probably too late to add or remove arguments from the 
> functions.
> It seems that the intent of the spec as it stands is that the title 
> parameter should show up in the session history list (shown e.g. when 
> you click the down arrow next to the forward button), but not in the 
> application's title bar.  We think this is confusing (as evidence, 
> observe that two browsers skipped this step!) and adds a lot of 
> complexity for a small amount of gain, so we're not in favor of this 
> approach.  If modifying the document's title in the session history list 
> is a desirable feature, then we could expose that property to the DOM 
> just as we expose document.title.
> Seeing as we're stuck with the title argument in pushState and 
> replaceState, we propose that it modify document.title in an intuitive 
> way:
> * Before we unload a history entry, we save document.title into the 
> history entry.
> * When we activate a history entry, we set document.title to the value 
> stored in the history entry.
> * When we pushState, we set document.title to the title parameter after 
> activating the new history entry.
> * When we replaceState, we set document.title to the title parameter.
> In the last two cases, if the title parameter is empty, we leave 
> document.title unchanged.
> We think this is a good compromise between complexity and functionality.

This seems reasonable. Try it. If it works I'll spec it. :-)

On Thu, 22 Jul 2010, Justin Lebar wrote:
> Just to follow up on this: We just pushed a change to Firefox to 
> completely ignore the title parameter, as WebKit does.
> We're getting close to locking down Firefox for the next release.  If we 
> want to do something more creative with the title parameter, now is the 
> time for action.

I would recommend that browsers experiment with what the most useful thing 
to do with this argument is. I'm happy to spec whatever gets implemented.

On Tue, 27 Jul 2010, Mihai Parparita wrote:
> I'm investigating a WebKit bug that occurs when navigating to hp.com and 
> then pressing the back button. The full details are at 
> https://webkit.org/b/42861, but briefly: onload hp.com sets 
> window.location.hash to #Product. In Firefox, IE, and Chrome, this does 
> not create a new session history entry (i.e. pressing the back button 
> goes to the page before hp.com), while in Safari/WebKit.org nightlies 
> pressing back from hp.com/#Product goes to hp.com (which then ends up 
> doing a redirect to a 404).
> It therefore seems like there is precedent for not creating a new 
> session history entry for JS navigation (even when not using 
> location.replace()) during (or even before) onload, but I'm not seeing 
> anything about this on 
> http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html
> https://webkit.org/b/42861 has more tests, but briefly, the behavior
> in the latest stable versions of these browser is:
> - Firefox will not create a session history entry if the navigation is
> executed inline, or during an onload handler
> - Chrome will not create a session history entry if the navigation is
> executed inline, or within 5 seconds of the onload handler firing
> - Safari will always create a session history entry
> - IE will not create a session history entry for hash changes during onload only
> My proposed change to WebKit is to not create a session history entry 
> for location changes that happen before onload fires if they are not in 
> response to a user gesture. I would also be modifying Chrome to remove 
> its custom logic for this and just inherit WebKit's.
> Does anyone see any compatibility problems with this? Should the HTML5 
> history section mention anything about navigations caused script vs. 
> user gestures*? I realize that replace() should obviate the need for 
> such a heuristic, but given that 1) other browsers seem to do this and 
> 2) sites like hp.com don't get it right, there may be a need for it.
> * It only alludes to something similar: "In addition, a user agent could 
> ignore calls to pushState() that are invoked on a timer, or from event 
> listeners that are not triggered in response to a clear user action, or 
> that are invoked in rapid succession."

IE's behaviour seems the narrowest; would it be acceptable? Failing that, 
how about any navigations until the end of the load event task?

The proposal here would be to just assume a scripted navigation is done 
with replacement enabled in the condition described above, right?

Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

More information about the whatwg mailing list