了解hashchange事件的执行顺序

Understanding execution order of the hashchange event

本文关键字:执行 顺序 事件 hashchange 了解      更新时间:2023-09-26

我有一个关于这段代码片段的问题:

window.location.hash=1;
$(window).on('hashchange', function() {
    alert('hello');
});
上面的脚本应该这样做:
  1. 设置位置哈希值为1
  2. 关于任何进一步的变化-> alert('hello')

这是问题:为什么hashchange在第一次执行的第一次调用?这个脚本不应该只改变哈希值而不发出任何警告吗?

我如何修复它,使其工作描述?

首先,你问:

为什么在第一次执行时第一次调用hashchange ?这个脚本不应该只改变哈希值而不发出任何警告吗?

要回答这个问题,我们可以深入研究规范。当导航到一个新的片段(即设置document.location.hash)时,规范要经过许多步骤,其中之一是:

  • 遍历历史到新条目,其中异步事件标志集。这将滚动到现在文档地址中给出的片段标识符。
  • 遍历历史的规范接着说:

  • 如果未设置异步事件标志,则同步执行以下步骤。否则设置异步事件标志;将任务排队以运行以下子步骤
    1. 如果state changed为true,使用PopStateEvent接口在Document的Window对象上触发一个名为popstate的可信事件,并将state属性初始化为state的值。此事件必须冒泡,但不能取消,也没有默认动作。
    2. 如果hash changed为真,则在浏览上下文的Window对象中使用HashChangeEvent接口,使用oldURL属性初始化为旧URL, newURL属性初始化为新URL,以名称hashchange触发可信事件。此事件必须冒泡,但不能取消,也没有默认动作。
  • 因此,所有这些加在一起意味着,当您运行代码时,hashchange的事件侦听器将在第14步的子步骤中的代码运行之前添加,并随后在设置哈希值时触发。


    我如何修复它,使其工作描述?

    要解决这个问题,还可以使用setTimeout(.., 0):

    将事件侦听器的添加排队。
    setTimeout(function() {
        $(window).on('hashchange', function() {
            alert('hello');
        });
    }, 0);
    

    由于是在设置散列之后将其添加到队列中,因此它将在上面步骤14中排队的任务之后添加到队列中,因此事件侦听器仅在事件触发后添加。

    在代码中使用计数器:

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

    不调用setTimeout的另一种修复方法是注册'hashchange'事件,然后设置hash的值。

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

    小提琴:http://jsfiddle.net/86829ryz/10/