Javascript 为什么不是';加载iframe时Safari中触发的popstate?

Javascript 为什么不是';加载iframe时Safari中触发的popstate?,javascript,html,safari,history,Javascript,Html,Safari,History,在Safari中,如果有iframe加载,并且用户通过返回或向前更改历史记录状态,则不会触发popstate事件,从而导致应用程序状态和窗口位置不同步 我认为一个活跃的XHR请求将导致相同的行为,但我还不能确认这一点 下面是一个JSFIDLE,它可以让您轻松地重现这个问题: 您只需按从1到6的顺序单击链接/按钮 在Safari 5.0.5中,输出为: (倒序排列,最重要的部分是顶部的状态比较) 然而在Chrome(11)或FireFox(4.0)中,输出看起来像: (请注意,这些状态是同步的)

在Safari中,如果有
iframe
加载,并且用户通过返回或向前更改历史记录状态,则不会触发
popstate
事件,从而导致应用程序状态和窗口位置不同步

我认为一个活跃的XHR请求将导致相同的行为,但我还不能确认这一点

下面是一个JSFIDLE,它可以让您轻松地重现这个问题:

您只需按从1到6的顺序单击链接/按钮

在Safari 5.0.5中,输出为:

(倒序排列,最重要的部分是顶部的状态比较)

然而在Chrome(11)或FireFox(4.0)中,输出看起来像:

(请注意,这些状态是同步的)

这是Safari中的一个bug吗?如果是的话,有人发现了解决方法吗


(同样有趣的是,FireFox和Chrome在页面加载时都会触发
popstate
事件。)

更新

据我所知,这个bug是

下面是WebKit中相应的和

我还没弄清楚这个bug是什么时候在Chrome上修复的。如果其他人有,我将非常感谢您的信息

我确实知道WebKit 533.21.1(Safari 5.0.5就是这么用的)中存在这个bug,并且已经被534.36(Safari/WebKit每晚)修复了——但是我不知道,也不知道是哪个中间版本引入了这个修复

有一种方法可以将Chrome版本映射到其WebKit版本

最重要的是,当存在任何活动网络流量(图像加载、Ajax请求等)时,而不仅仅是iFrame时,就会出现此错误。如果您试图实现历史API支持,或者您正在使用的最新版本(默认情况下已启用历史支持),此错误可能会严重影响您的应用程序


第二次更新

我想我找到了引入修复程序的WebKit版本(534.10)。因此,如果您使用jQuery和Asual的地址插件,下面是一个实用的解决方案:

if (!($.browser.webkit === true && parseFloat($.browser.version) < 534.10)) {
    // only enable state support if WebKit version >= 534.10
    $.address.state("/base/path");
}
同样有趣的是,Safari现在与Chrome和FireFox的行为相匹配,在页面加载时触发popstate

  • Img/script/iframe加载将破坏popstate,但XHR不受此bug的影响
  • 文件加载前的后退/前进将延迟。加载时,我们将获得一个popstate。(即使有多个后退/前进,也只会弹出最后一个状态。)
  • (在Android 2.2和iOS 4.3.3上的Safari下测试)

    因此,解决办法是:

    使用XHR而不是img来跟踪/预加载加载事件后的任何内容

    如果用户在加载事件之前做了两次或两次以上的向后/向前操作,我们可能仍然会遇到问题,但如果加载时间短,用户很少会执行多个操作,因为最终状态是正确的,所以我认为这是可以的

    另一个解决办法是:

    使用计时器查看url,如果在没有popstate的情况下更改了url,请自己动手做脏活。(作为这个bug的评论,Facebook曾经使用过这个解决方案。)

    但是这个方法太复杂了,因为您应该将状态序列化/反序列化为url或localstorage/sessionstorage,就像您没有历史API一样。所以我认为这不是一个可以接受的解决办法

    [1305665609499] /
    [1305665609499] vs
    [1305665609499] /
    ---------------
    [1305665608360] iframe loaded
    ---------------
    [1305665607770] popstate: /
    [1305665607770] $.address change: /
    [1305665607758] (did popstate or $.address change trigger?)
    [1305665607758] called history.back()
    [1305665607758] appended iframe
    ---------------
    [1305665606870] popstate: /node
    [1305665606869] $.address change: /node
    ---------------
    [1305665606150] popstate: /
    [1305665606149] $.address change: /
    ---------------
    [1305665605551] $.address change: /node
    ---------------
    [1305665604808] $.address change: /
    ---------------
    [1305665603354] iframe loaded
    ---------------
    [1305665602688] $.address change: /neonsilk/muHk8/show/
    [1305665602682] $.address init
    [1305665602676] popstate: /neonsilk/muHk8/show/
    
    if (!($.browser.webkit === true && parseFloat($.browser.version) < 534.10)) {
        // only enable state support if WebKit version >= 534.10
        $.address.state("/base/path");
    }
    
    [1305666598481] /
    [1305666598481] vs
    [1305666598480] /
    ---------------
    [1305666597469] iframe loaded
    ---------------
    [1305666597300] popstate: /
    [1305666597298] $.address change: /
    [1305666597270] (did popstate or $.address change trigger?)
    [1305666597269] called history.back()
    [1305666597269] appended iframe
    ---------------
    [1305666596605] popstate: /node
    [1305666596605] $.address change: /node
    ---------------
    [1305666596008] popstate: /
    [1305666596008] $.address change: /
    ---------------
    [1305666595555] $.address change: /node
    ---------------
    [1305666595142] $.address change: /
    ---------------
    [1305666578600] iframe loaded
    ---------------
    [1305666578400] $.address change: /_display/
    [1305666578400] $.address init
    ---------------
    [1305666577964] popstate: /_display/