最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Understanding execution order of the hashchange event - Stack Overflow

programmeradmin2浏览0评论

I have a question for you regarding this code snippet:

window.location.hash=1;

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

The script above should do this:

  1. set the location hash to 1
  2. on any further change -> alert('hello')

This is the problem: why is hashchange called at the first time of the first execution? Shouldn't this script change only the hash without any alert?

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

I have a question for you regarding this code snippet:

window.location.hash=1;

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

The script above should do this:

  1. set the location hash to 1
  2. on any further change -> alert('hello')

This is the problem: why is hashchange called at the first time of the first execution? Shouldn't this script change only the hash without any alert?

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

Share Improve this question edited Oct 12, 2015 at 18:26 James Thorpe 32.2k6 gold badges75 silver badges94 bronze badges asked Oct 12, 2015 at 17:44 BillyBellyBillyBelly 5233 silver badges14 bronze badges 2
  • 7 The actual update of the hash might happen in the next tick of the event loop. – Felix Kling Commented Oct 12, 2015 at 17:47
  • 4 Try putting the event handler in a setTimeout() – Rory McCrossan Commented Oct 12, 2015 at 17:50
Add a ment  | 

3 Answers 3

Reset to default 7

Firstly, you ask:

why is hashchange called at the first time of the first execution? Shouldn't this script change only the hash without any alert?

To answer this, we can delve into the specification. When navigating to a new fragment (ie setting document.location.hash), the specification goes through a number of steps, one of which is:

  1. Traverse the history to the new entry, with the asynchronous events flag set. This will scroll to the fragment identifier given in what is now the document's address.

The specification for traversing the history goes on to say:

  1. If the asynchronous events flag is not set, then run the following steps synchronously. Otherwise, the asynchronous events flag is set; queue a task to run the following substeps.
    1. If state changed is true, fire a trusted event with the name popstate at the Window object of the Document, using the PopStateEvent interface, with the state attribute initialized to the value of state. This event must bubble but not be cancelable and has no default action.
    2. If hash changed is true, then fire a trusted event with the name hashchange at the browsing context's Window object, using the HashChangeEvent interface, with the oldURL attribute initialized to old URL and the newURL attribute initialized to new URL. This event must bubble but not be cancelable and has no default action.

So all of that taken together means that when you run your code, the event listener for hashchange will be added before the code in the substeps of step 14 is run and will subsequently be fired when the hash is set.


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

To fix it, you can also queue the adding of your event listener using setTimeout(.., 0):

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

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

use a counter inside your code:

var counter = 0;

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

Another way to fix it without calling setTimeout would to register the 'hashchange' event and then set the value of hash.

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

alert('Hash Updated');
window.location.hash = "1";

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

发布评论

评论列表(0)

  1. 暂无评论