部分浏览器会记忆iframe的src属性

问题描述

当一个<iframe>存在于页面中,刷新页面(并非第一次请求,而是按F5或单击刷新按钮进行刷新)时,浏览器会记住该<iframe>最后的src地址,并自动渲染<iframe>,除非<iframe>满足以下条件:

  • <iframe>src属性满足^#+$这个正则,即由若干个#组成。
  • 由javascript通过createElement动态创建iframe,并且在<iframe>加入到DOM之前就设置了src属性。

该问题影响的浏览器为Firefox3.6+和IE6-8,其中Firefox3.6以前版本没有测试,但估计也有这个问题。最简单的重现该问题的代码如下:

<!DOCTYPE html>  
<html>  
<head>  
    <meta charset="utf-8" />
    <title>测试</title>
</head>  
<body>  
    <iframe></iframe>
    <script>
        var iframe = document.getElementsByTagName('iframe')[0];
        iframe.src = 'inner.htm';
    </script>
</body>  
</html>  

其中inner.htm中有什么内容是不重要的,具体的表现可以看下图,上侧为每一次加载页面时的请求图,下侧为按F5刷新时的请求图:

刷新时网络请求图

解决方案

看了百度统计的结果,发现其实很多来自搜索引擎的访问只是在找问题的解决方案,因此今后对于问题类的博文,就将解决方案先写在前面,其他的关于如何发现以及问题的深入分析放在后边,毕竟不是所有人都需要挖得那么深的。

  • 对于<iframe>写在html中的情况,将<iframe>src设为\#,或者由若干个#组成的字符串即可(#,##,###..都可以)。
  • 对于使用javascript调用createElement创建出来的<iframe>,需要在将该<iframe>加入到DOM之前就设置好src

细节方面

Q:猜测的原因?

A:根据网友的说法,部分浏览器会记住<iframe>的src,在刷新的时候立刻加载并渲染,某种程度上这是一种优化。

然而这种行为,在某些情况下却成了糟粕,作者认为这不是规范期望的行为,因此定义成了BUG。


Q:到底是请求了2次,还是渲染了2次?

A:确实是渲染了2次,可以通过以下方法得到重现:

  1. 在inner.htm中添加script,执行一个alert
  2. 将设置<iframe>src的代码变为setTimeout(function() { iframe.src = 'inner.htm'; }, 3000);

经过以上步骤,重新进行测试,会发现刷新页面时,alert执行了2次,即可判断浏览器对inner.htm进行了2次的解析和渲染。


Q:与浏览器的缓存是否有关?

A:禁用浏览器的缓存并不能解决此问题。


Q:如果移除了iframe?

A:一但设定了iframe的src属性,即便移除了该iframe,在下次刷新时依旧会有2次渲染行为。


Q:对于使用javascript动态创建出来的iframe,也是2次渲染?

A:不会,因为第一次对inner.htm请求时,该iframe根本不存在,因此这个请求会被abort。