000
000

Reputation: 27227

Modifying location.hash before page load

Consider a page that contains only this script tag:

<script type="text/javascript">
  window.location.hash = 'testing';
  window.history.back();
</script>

If you go to google.com, then load that page, you'll see the hash update in the address bar, but then the page goes back to Google! I expect it to just remove the #testing hash.


If I wrap it in a long timeout, it works as expected:

<script type="text/javascript">
  setTimeout(function () {
    window.location.hash = 'testing';
    window.history.back();
  }, 1000);
</script>

The address bar briefly flashes the #testing hash, and then it is removed.


This means that, at some point in time, changes to the location.hash are propagated to the history api. There must be some event that fires when this behavior changes.

I've looked through the list of events on mdn and found these:

pageshow: The pageshow event is fired when a session history entry is being traversed to. (This includes back/forward as well as initial page-showing after the onload event.)
load: The load event is fired when a resource and its dependent resources have finished loading.

Neither of these events fix the issue. I tried:

<script type="text/javascript">
  window.addEventListener('pageshow', function () {
    window.location.hash = 'testing';
    window.history.back();
  }, false);
</script>

and the same with the load event. The address bar flashes the #testing hash, then the browser returns to the previous page.


How can I detect if modifying location.hash is safe to do?

Upvotes: 2

Views: 827

Answers (1)

000
000

Reputation: 27227

It seems that the load event is on the right track, but with a slight twist. The history api picks up the change one tick after the load event.

That is, this code is problematic:

<script type="text/javascript">
  window.addEventListener('load', function () {
    window.location.hash = 'testing';
    window.history.back();
  }, false);
</script>

But this code correctly removes the hash:

<script type="text/javascript">
  window.addEventListener('load', function () {
    setTimeout(function () {
      window.location.hash = 'testing';
      window.history.back();
    }, 1);
  }, false);
</script>

I am not sure why this is, and I can not find any spec that states this should be the case, but this is what I found after some trial and error.

2023 update: The behavior still exists as of Chrome v111 and Safari v16.3, but is not reproducible on Firefox v111.

Upvotes: 1

Related Questions