[whatwg] HTML5 History Management

Ian Hickson ian at hixie.ch
Thu Aug 13 16:20:41 PDT 2009

On Wed, 5 Aug 2009, Nathan Hammond wrote:
> With regards to pushState not triggering a hashchange event, I like it, 
> but I do want to be absolutely sure that all implementers get this 
> right. So, could we clarify this in the spec? Right now I think that the 
> spec could be read where since it adjusts the document's current address 
> it might should cause a hashchange event. Providing this specific 
> example would do the trick.


> Related, is window.location.hash = "newhash"; supposed to trigger a hashchange
> event? (Is this specified? I couldn't find it.) I do believe it does in IE8,
> but I don't have IE8 available to me at this moment to check.

Yes, and yes, it is specified. It triggers a navigation, which eventually 
gets around to the part that fires hashchange.

> > > 2. Specify a method to allow access to the history stack. (At least 
> > > readable within the context of same-origin, possibly mutable.)
> > > 
> > > This would allow for understanding on the client side of a user's 
> > > path through the site, even after navigating away from the page. If 
> > > this is not implemented the absolute first thing I will be 
> > > implementing is a method to track this information, a rather large 
> > > duplication of effort for something that could easily be made 
> > > available. This would involve a something like currentstate = { 
> > > _previous: currentstate, title: window.title, newval: true }; plus a 
> > > form-based storage mechanism to repopulate state in case the user 
> > > exits on a page which they manually changed the hash to get to 
> > > (which would not have access to the data object upon revisiting 
> > > later since there wouldn't be one stored with that history state).
> > > 
> > > I'm aware of the privacy ramifications, but at the same time, I'm 
> > > going to be exposing those exact same concerns with the above 
> > > method.
> > 
> > It turns out to be quite complex to expose this in the API currently, 
> > because the History object exposes a mix of all the various frames at 
> > once, and you can get to the History object of cross-origin frames, 
> > and there's some other legacy baggage here also (e.g. history.length).
> > 
> > Since it's not entirely clear what the use case is, and since you can 
> > do it to some extent already using onload, onhashchange, and 
> > onpopstate, I'd rather just let authors reimplement this themselves at 
> > this point, and maybe revisit this in a future version.
> Complexity. Bah! (Then again, you don't have to tell me.) The use case I 
> find is pretty simple: in the event that there are two separate ways to 
> get to a specific page in the app I need to know how the person got 
> there. Or this could be used to provide content tailored specifically to 
> that user based upon their history (whether suggestions, ads, or help 
> text). Really though, this point is far less critical (as it is easy 
> enough to handle in client code) and does greatly increase the 
> complexity for getting all implementers on board. If this *isn't* 
> implemented however, the point below becomes more critical for being 
> able to successfully track state in client code...

I don't really understand the scenario under which those use cases would 
be relevant. Can you show an example of someone doing something like this 

> > > 3. Specify a method to modify the current history state without adding a
> > > new history point.
> > 
> > Assuming you don't mind causing the page to reload, you can use
> > history.replace(). I'm not sure what it would mean to replace the history
> > state without changing the Document or anything, though.
> > 
> > > This would alleviate the need for the (incredibly brittle) form-based
> > > storage mechanism I describe above.
> > 
> > Can you use sessionStorage for this?
> I should have stated this one with a goal: the ability to ensure that 
> the popstate event always fires with a full understanding of the 
> (app/page) state when navigating through history. This would be lost 
> when a user manually changes the hash. With that as my goal, 
> history.replace does not achieve what I am trying to accomplish. Neither 
> does pushState without a URL as that still registers a new history 
> point.

All the information about the state really should be in the URL, such that 
the state of the app after the user manually changes the hash, and the 
state of the app after the user returns to a point in the history where he 
had manually changed the hash, really should be the same. I don't think we 
should encourage cases where the same URL can correspond to multiple 
states, which this would encourage.

> > > 4. Specify additional properties on the hashchange event.
> > > 
> > > Lots of possible useful information with the number one most 
> > > important being the new hash that triggered the event to prevent 
> > > race conditions reading window.location.hash. Other fun things that 
> > > are a bit more pie in the sky: the previous hash and knowledge of 
> > > how it was triggered (manually? pushState? window.location.hash = ? 
> > > window.location.href = ?).
> > 
> > What are the use cases?
> My primary concern here is based upon my experience with having to poll 
> to emulate hashchange. In this scenario it is quite possible to have two 
> unique actions which are only registered as one (depending upon if the 
> hash checking is reactive and responds to a new hash or proactive and 
> sets the hash as part of the action and notifies the listener to 
> ignore). Thinking about it more you can almost get rid of the race 
> condition since hashchange events will always be triggered serially by 
> monitoring from the beginning the current value. This value would only 
> need to be updated when a hashchange event occurs--but that event must 
> identify the updated value of the hash that triggered the hashchange 
> event.

I really don't follow.

Imagine you're updating what's visible based on the hash, and the user 
changes the hash twice in a row quickly such that by the time you get the 
first event, the location's already changed again. Why wouldn't you be 
happy to ignore the first location?

> Otherwise there is some possibility of:
> 1. Navigation request.
> 2. Script loads, stores initial hash.
> 3. Hash changes and fires hashchange event 1.
> 4. Hash changes and fires hashchange event 2. (~12ms apart is about the limit)
> 5. hashchange event 1 is processed, reading location.hash reflects the value
> from event2.

Could you describe a scenario in which that's a problem?

> The way it appears to me now, re-reading, the spec is written in a way 
> that it only identifies exactly what is to be done, and if not 
> explicitly mentioned no other actions are taken. Reading the spec in 
> "fill-in-the-blank" mode, which is how I did originally, without my new 
> insight into how it appears to be written and knowledge of how things 
> work right now had me jumping to conclusions about what is supposed to 
> happen.

Ah, HTML4's legacy. Yeah, fill-in-the-blank mode is definitely not needed 
and is indeed harmful with HTML5. :-)

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