对于iframe,我是比较少做测试的,今晚由于我的一个问题“有没有办法让页面HTML内容和其他资源并行加载”引发了我和瓶子之间的一番关于iframe的测试。
首先是由于我的一个误解“iframe会阻塞后面资源的下载”以及上面的问题引发的“浏览器解析页面和下载资源的顺序问题”开始。在Webkit的官方博客中发表了这么篇文章:《How WebKit Loads a Web Page》,讲述页面解析HTML和下载资源的机制。文中就说明了Webkit在加载一个页面的时候存在两个下载通道,一个用于加载html document,另一个用于加载子资源(图片、CSS、JS等等),并且这两个通道存在时间顺序问题(查看原文或者下面的图示即可了解),这就说明了“让页面HTML内容和其他资源并行加载”就目前来说是不可能实现的,因为这是由浏览器内部的加载页面的机制决定了。
在这篇文章里,跟瓶子就“Frames”这个字眼见解有些不同,他认为这就是跟普通页面的iframe一样的意思(这也是接下来一堆测试iframe的导火线),而我曾经在某篇En文里看过Firefox中解析HTML页面的时候,也提到了Frame这个字眼,而它所说的Frame并不是普通html中的iframe,而是相当于一个“暗箱”,或者说是一个“容器”,来解析HTML页面内容。这个问题未得到证实,就不多说了。
之后我就凭记忆说了一句“加载iframe会阻碍后面的元素的加载”,我的本意是说,当iframe中有js、图片、css等资源需要加载时,会阻塞主页面中iframe后面资源的加载。可是经过他的测试,发现说“主页面的html和iframe的html是并行加载的”。刚开始我就纳闷了,就拿出《高性能网站建设进阶指南》来查看关于iframe的内容,发现书中并没有关于“加载iframe会阻碍后面的元素的加载”的论述,而是叙述了当iframe前面有CSS或者JS资源的时候,会阻塞iframe的加载(测试页面),如果放到iframe其后的话,则会iframe和主页面会并行加载(测试页面)。同时书中也指明了一点“iframe会阻碍主页面onload事件的触发”。
经过这一番测试,不得不承认是我的失误,记错了~
但是我在测试过程中,通过观察firebug和HTTPWatch生成的HTTP瀑布图发现了一个比较有趣的事情:当iframe在js、图片、css等主页面资源的前面的时候,在HTTP瀑布图中显示iframe内的资源都是后于主页面的资源加载的。我就纳闷了,这么奇怪的问题。接下来我就写了一个测试页面,页面中iframe内的js文件中定义了一个函数,而且文件有100多K大小;在主页面的fulljsmin.js文件中调用该函数,文件很小(测试页面)。通过测试更有意思的是,成功调用了该函数,没有出现未定义的错误,这不是跟HTTP瀑布图中显示的不符合吗?下面是在firebug和HTTPWatch下的HTTP瀑布图:

同时,在Chrome下用Inspect插件来测试,也都发现了这样的情况。虽然在IE8下HTTPWatch中显示iframe并没有和主页面并行加载,但是出现的问题都基本跟上面所述一致。这难道是firebug、HTTPWatch、Inspect的一个bug?不可能同时都出现这个问题吧?我想问题还应该是出在页面加载iframe的机制上。
对于这个问题,我最初的想法是主页面在加载iframe的时候会开启另外一个进程来加载iframe里面的资源,但是浏览器普遍都只能是两个资源并行下载,iframe内也同样难逃这条规则。所以这个想法就错误了,而瓶子对于这个页面同时加载主页面的资源和iframe内的资源的看法是:
- 父页面html加载->html解析
- 如果有iframe,就开一个iframe线程下载html,重复步骤1
- 把页面其他要请求的元素放入一个加载队列,这个队列是全局的,如果是iframe的html解析的时候,也会被加入到这个队列里。但是最终会出现的顺序可能有所不同,有的浏览器应该会等html全部分析完再开始执行加载队列,有的则是一边解析一边对队列进行执行。对于第一种情况,出现的顺序应该是:主页面的内容先加载,iframe里面的内容会最后连续加载对于第二种情况,出现的顺序可能是交叉的,不过iframe的加载应该大多集中在一处。
第一点看法是毋庸置疑的,但是第二点所说的“开一个iframe线程下载html,重复步骤1”,这点或许需要说明一下,这开一个iframe线程是受到浏览器通常只能同时两个并发下载数的限制的,所以这里的新开线程可能会受到CSS、JS文件的影响,就像开头说的,CSS、JS在iframe前面的时候,会阻塞iframe的加载(测试页面,这次在页面中嵌套了两个iframe)。从下图可以说明,在iframe前面有CSS、js等外联文件的时候,阻塞是比较严重的:
对于第三点的将iframe中的资源加入加载队列,这里我就有点迷糊于“在什么位置加入加载队列”。如果简单的从HTTP瀑布图来说的话,第一种情况是比较在理的:在页面开始加载资源的时候,自动生成一个加载队列,遇到iframe的时候,就将iframe中的资源加载到队列的末尾,可是这又不符合上面的函数调用的测试。所以我初步总结为:在Firefox、Chrome、IE中,当主页面开始加载子资源的时候,自动生成一个加载队列,当遇到iframe的时候,就把iframe里的子资源加入到加载队列里,主页面后续的子资源再加入到加载队列中。当页面内有几个iframe的时候,也是这个理。
写本文时我都还存在很多的疑问需要慢慢揭开,同时也希望对这方面有研究的朋友,能指明一二,共同探讨~
我那几条说的大部分靠猜测,还需要实践证明。非常敬佩你的实践精神,自愧不如啊~~~
过奖过奖了~共同进步……
欢迎来我的博客做客
不知道楼主能不能看到这个回复。
有些疑问:
1 我ie6中遇到1frame加载时,页面会跳2下,首先给人的感觉是主页面出来,然后再加载iframe的内容,所以页面跳了一下。现在我就是想让他们同步加载。
2 在iframe页面中引了js,在主页面中调用,会出错,不会出现你所的那种情况,
可以通过mail交流。。
我用struts2 和 jquery, 不知道jquery有没有影响 ,主页面是jquery的tabs,页面量比较大,在iframe的action中设置断点,显示是在主页面加载后才进入这个断点,。。。当然这个也不是那么准确。。
你也可以答在这里,我会回来看的
要让iframe和主页面同步加载,是不可能的,肯定是主页面先加载HTML并解析,遇到iframe的时候,又会启动一个HTML解析器,对iframe进行跟主页面一样的解析过程,但是iframe中的资源会跟主页面的其他的资源并行加载,如果是js的话,就会阻塞主页面后续资源的加载。
在iframe中加载的js想要操作主页面,这个一是查看是否跨域了,二是调用方法上是否有错
楼主:我有一问题请教
我有三个页面,a.jsp,b.jsp,c.jsp和一个js文件:b.js
a.jsp中包含两个iframe,分别是a1和a2
a1加载了b.jsp,a2加载了c.jsp
c.jsp中也有一个iframe为c1吧
b.js是b.jsp对应的js文件,我现在想在b.js中为c1这个iframe赋值
但是我在写b.js文件的时候,发现是先将我的这个文件中的代码都执行完,才会去加载c.jsp,这样一来,我就无法为c1这个iframe赋值了。求解。