Understanding the hashchange event execution order

I have a question for you regarding this piece of code:

window.location.hash=1; $(window).on('hashchange', function() { alert('hello'); }); 

The script above should do this:

  • set the location hash to 1
  • upon any further change -> alert('hello')

This is the problem: why is the hashchange call called for the first time the first execution? Doesn't this script only change the hash without warning?

How can I fix it so that it works as described?

+5
source share
3 answers

First, you ask:

why is hashchange called for the first time the first execution? Doesn't this script only change the hash without warning?

To answer this question, we can delve into the specification . When switching to a new fragment (i.e., setting document.location.hash ), the specification goes through several steps, one of which is:

  1. Move the story to a new record with the asynchronous event flag set . This will scroll to the fragment identifier specified in what is now the address of the document.

The story traversal description says:

  1. If the asynchronous event flag is not set, follow these steps synchronously. Otherwise, the asynchronous event flag is set; queue for the following substeps .
    • If the state is changed correctly, fire up a trusted event named popstate in the Window object of the document using the PopStateEvent interface, with the state attribute initialized with the state value. This event should bubble, but not be canceled, and has no default action.
    • If the hash is changed, that’s true, then fire up a trusted event named hashchange in the context of the viewport. Window object using the HashChangeEvent interface, with the oldURL attribute initialized by the old URL and the newURL initialized attribute to the new URL. This event should bubble, but not be canceled, and has no default action.

So, all this together means that when you run your code, an event receiver for hashchange will be added before the code is executed in the sub-steps in step 14 and subsequently will be launched when the hash is set.


How can I fix it so that it works as described?

To fix this, you can also add an event listener to the queue using setTimeout(.., 0) :

 setTimeout(function() { $(window).on('hashchange', function() { alert('hello'); }); }, 0); 

Since you add this to the queue after installing the hash, it will be added to the queue after the task queued in step 14 above, and thus the event listener is added only after the event has been fired.

+3
source

use a counter inside your code:

 var counter = 0; $(window).on('hashchange', function() { if (counter) alert('hello'); counter++; }); 
0
source

Another way to fix this without calling setTimeout is to log the hashchange event and then set the hash value.

 $(window).on("hashchange",function() { alert('Invoked due to hash change' + window.location.hash); }); alert('Hash Updated'); window.location.hash = "1"; 

Fiddle: http://jsfiddle.net/86829ryz/10/

0
source

Source: https://habr.com/ru/post/1233541/


All Articles