在我上篇文章里,我提到一种使用iframe完成无阻塞脚本加载的方式,因为我对iframe的偏见很大,所以上篇文章里我没有展开讨论这个问题。

  文章发表后有位网友问了我这样一个问题,下面是他问题的原文,如下所示:

我一个电商后台系统,用的表格控件是flexigrid,,里面是个iframe来的,每一个tab就是一个iframe,现在遇到的问题就是,如果其中一个或者多个iframe在加载数据,还没加载完,如果这个时候,我再去开一个tab,也是查找数据,可能数据量很大,或者提交数据(其他的iframe可能还在加载数据),这个时候很容易出现浏览器卡死,一直转圈的现象,这个跟你说的这个js阻塞也有关系吧。跟这个js单线程的特性,线程阻塞有多大的关系~~

  

  这个现象很有趣,就和我在上篇文章里谈到我思考无阻塞脚本加载的源起一样,研究这个朋友提供的现象应该也能给我们很大的收获。

  首先,这位朋友提到“如果其中一个或者多个iframe在加载数据,还没加载完,如果这个时候,我再去开一个tab,也是查找数据,可能数据量很大,或者提交数据(其他的iframe可能还在加载数据),这个时候很容易出现浏览器卡死,一直转圈的现象”,这个现象让我有个疑问:

  首先我们要明确页面使用iframe时候等于一个页面里嵌套一个页面,iframe的src指向的页面其实和父页面是相对独立的,那么一个带了iframe的页面,父页面的加载过程和iframe加载的过程是怎样的关系了,具体点就是父页面是不是要等待iframe页面里所有资源加载完毕后才会触发onload事件,页面的onload事件触发了,也就代表页面的忙指示结束,而忙指示是我们衡量页面是否被阻塞的一个重要标志。

  幸运的是有人已经帮我们做了这个实验,下面我来描述下这个实验的方式:

  阻塞加载方式即在页面直接写:

<iframe src=”url”></iframe>

  

  Iframe的url指向的页面分为四种类型:

  1.url指向一个空文档,空文档不是指页面指向的网页不存在,而是指向网页里只有最基本的html,例如:

<html><head></head><body><p>ddddd</p></body></html>

  

     这时候iframe加载就不会因为内部静态资源而被阻塞。

  2.url指向的页面里包含图片;

  3.url指向的页面包含外部脚本;

  4.url指向的页面包含外部css样式文件。

  上面的静态资源,实验设计者都让它们的加载有延时,实验的结果是令人失望的,这些静态资源加载都会阻塞父页面的加载,即iframe的加载延长了忙指示结束的时间。

  接下来实验者又做了一个实验,这个时候在父页面里iframe的src设为空,然后使用javascript代码给iframe设定src的值,赋值的时机也是在onload事件之前,而url指向和上个实验一致,结果是在以webkit为内核的safari和chrome下,页面加载明显变快,iframe的加载没有阻塞父页面的加载,但是在其他浏览器下这个结果是令人失望的,阻塞任然存在,甚至比以前还要严重。

  Iframe的加载是能阻塞父页面的加载,上面朋友的现象描述里:一个iframe没有加载完毕,用户可能就会选择另外一个iframe,另一个iframe也在加载新页面,这个描述说明了,这个朋友的iframe的src应该都是使用javascript设置,而不是事先填好的,他的场景符合实验二的情况。这里又会产生一个问题,第一个iframe可能是和主页面资源加载同步的,即主页面很有可能还没触发onload事件,为啥用户还能触发iframe的加载操作,按我原来的逻辑,这时候页面应该是不能接收任何响应的,这里我要纠正下这个观点,页面被阻塞不代表页面会停止接收用户的所做的相关操作,例如在ie浏览器,如果页面被阻塞,用户点击了两次按钮,浏览器会认为用户的操作是有效的,会将用户的操作加入到浏览器执行的UI线程里的,这是浏览器对于性能不佳网页的一个妥协做法。

  Iframe阻塞页面加载的问题还有更多深层次的原因,首先iframe页面dom元素中加载最慢的,大家可以看看下面这张图:

  我们使用dom在页面里创建iframe、a、div、srcipt和style节点,第一栏是创建10个节点,第二栏是创建100个节点,第三栏是创建1000个节点,数值是代表创建的时间,由此可见创建iframe越多,耗时越长,可见iframe本身就是页面性能的瓶颈所在。

  在前面文章里我讲到网站为了提升页面资源并行下载的,可以将通用的静态资源放到一个独立的域名下,跨域可以增加页面连接数,使用iframe的页面会有两个url,iframe能达到增加并行下载的目的吗?如果iframe的url和父页面的url不同,能不能增加我没有做过测试,无法回答,但是针对这个朋友的问题,他使用的iframe的url肯定会和父页面在同一个域下面,因为他使用的iframe目的是为了布局而不是为了嵌入其他web的页面,iframe和父页面同域的结果就是并发连接数是不能被增加的,因为iframe是指向一个完整的页面,在加上上面说的iframe其实也会阻塞页面的加载,因此这个场景下就等于浏览器同时加载两个独立页面却要遵守一个页面加载的方案,结果自然是页面会变得更慢。

  由于这个朋友的应用是内部的控制台,因此它的网站绝对不会有做那些提升网站性能的优化工作,网站优化里有一条就是:将外部的css文件和js文件缓存,所以这个朋友网站肯定会出现这个问题,第一个iframe还没加载完,用户打开了第二个iframe,这两个iframe使用的外部css文件和js文件可能大部分相同,但是它们在每个iframe里都会被重新加载,而且第一个iframe没有加载完毕,还会阻塞第二个iframe对静态资源的加载,如果开启的iframe越多,阻塞就越加严重,后果自然也是网站越来越慢。

  那么我们该怎么帮这个朋友解决他的问题了?最好的方式就是将iframe去掉,使用div来实现选项卡,这么做太残酷,要重构整个前端代码,这个朋友问我的目的就是不想这么干了。

  所以要考虑下代价较少的方法,下面是我晚上想到的,希望看了我博客的大牛们也会有更多更好的建议,我想到的如下:

  1. 这个网站的性能问题源自于iframe使用过多,那么我们应该减少iframe,所以这个朋友可以将页面主页面的布局改为传统布局,即菜单放到页面左边,页面上去掉选项卡,工作区只有一个iframe,这样就只需要修改主页面就行了。不过这样会减少一个用户友好的功能,这个朋友使用选项卡好处就是iframe能有记忆功能,但是左边菜单一个iframe后没点一次菜单就得重新打开页面,不过失去这个功能和性能损失比起来我相信还是性能更加重要。
  2. 将页面的静态资源添加缓存功能,缓存外部的js文件、css文件还有图片,我不知道这个朋友服务端使用什么语言开发,如果是java的话,生产的web容器应该是tomcat,jboss之流了,这些java的web容器怎么设置静态资源缓存我还真的不清楚,最好还是将静态资源放到apache,ngnix这样的web服务器下,如果使用静态资源服务器最好提供一个和主服务器的域名不一样的访问地址,这样还可以提升浏览器并发下载的连接数。

  文章写毕,最后再重申一下希望有大牛看了本人的文章,能告诉我们更多更好的方式。

通过分析iframe和无阻塞脚本关系能让我们更懂iframe的更多相关文章

  1. javascript性能优化:创建javascript无阻塞脚本

    javaScript 在浏览器中的运行性能,在web2.0时代显得尤为重要,成千上万行javaScript代码无疑会成为性能杀手, 在较低版本的浏览器执行JavaScript代码的时候,由于浏览器只使 ...

  2. JS脚本文件的位置对页面加载性能影响以及无阻塞脚本(javascript)模式

    JS的阻塞特性:当<script>出现的时候,页面必须等待脚本文件的加载.解析.执行完毕后才能继续进行页面的渲染.不管脚本文件是以内联形式还是外部引入的形式出现在<script> ...

  3. 探真无阻塞加载javascript脚本技术,我们会发现很多意想不到的秘密

    下面的图片是我使用firefox和chrome浏览百度首页时候记录的http请求 下面是firefox: 下面是chrome: 在浏览百度首页前我都将浏览器的缓存全部清理掉,让这个场景最接近第一次访问 ...

  4. 无阻塞加载和defer、async

    无阻塞加载 把js放在head里,浏览器是怎么去执行它的呢,是按顺序加载还是并行加载呢?在旧的浏览器下,都是按照先后顺序来加载的,这就保证了加载的js依赖不会发生问题.但是少部分新的浏览器已经开始允许 ...

  5. 高性能 js -- 无阻塞加载脚本

    参考: <<高性能JavaScript>> Nicbolas C. Zakas 著 javascript代码的下载和执行过程会阻塞浏览器的其他进程, 比如页面的绘制, 遇到&l ...

  6. 无阻塞加载外部js(动态脚本元素,XMLHttpRequest注入,LazyLoad)

    动态脚本元素即在js中去创建<script>标签加载外部js并执行,这样加载的好处是文件的下载和执行过程不会阻塞页面的其他进程.通过下面两个例子对比出效果 <!DOCTYPE htm ...

  7. 无阻塞加载js,防止因js加载不了影响页面显示

    浏览器加载静态资源和js的方式都是线性加载,所以一般情况可以将js放到</body>前,防止UI线程的阻塞. 而某些时候我们既希望js在整个网页的头部就加载,又担心js阻塞导致网站加载缓慢 ...

  8. Web Worker无阻塞UI的牛逼技术,html5,可惜无法敢于UI

    众所周知,JavaScript是单线程的,JS和UI更新共享同一个进程的部分原因是它们之间互访频繁,但由于共享同一个进程也就会造成js代码在运行的时候用户点击界面元素而没有任何响应这样的情况,这么糟糕 ...

  9. 使用Interlocked在多线程下进行原子操作,无锁无阻塞的实现线程运行状态判断

    巧妙地使用Interlocked的各个方法,再无锁无阻塞的情况下判断出所有线程的运行完成状态. 昨晚耐着性子看完了clr via c#的第29章<<基元线程同步构造>>,尽管这 ...

随机推荐

  1. DEV设计之自动流水号,DEV专家解答,自己折腾了半天也没有搞定,怪英文不好

    () 老外专家给了回答,结果没有全到懂,又折腾了20分钟朋友提示才搞定 获取一个自动增加1的流水号值, 第一个参数是本事的数据库连接对象,第2个参数是也这个值为唯一标识返回来一个增量的值,第三个好像没 ...

  2. 110.Balanced Binary Tree Leetcode解题笔记

    110.Balanced Binary Tree Given a binary tree, determine if it is height-balanced. For this problem, ...

  3. vi

    e! 放弃所有修改,从上次保存文件开始再编辑 shift+g 最后一行 gg 第一行 u 恢复上一次操作 如果查找下一个,按"n"即可. set nu 显示行号 编辑模式下111g ...

  4. Linux CPAN Perl 模块安装

    当我们想使用某些Perl模块的时候,很可能会遇到当前系统不存在这个模块的情况,这时我们可以通过使用CPAN来对相应的模块进行获取,下面就介绍一下CPAN的使用方法.首先,我们可以用perl -e 'u ...

  5. 用ajax动态获取数据显示在highcharts上

    html代码(index.html) <html><head> <meta charset="UTF-8" /> <title>Hi ...

  6. 第三章 Docker 入门

    第三章 docker 入门 3.1 确保docker已经就绪 首先查看docker程序是否存在,功能是否正常 [#3#cloudsoar@cloudsoar-virtual-machine ~]$su ...

  7. Unity 编辑器的 界面布局 保存方法

    在软件界面的右上角(关闭按钮的下方),点击  layout  (界面)的下拉箭头. 弹出选项中的 save layout....(保存界面选项),输入命名,就可以生成这个界面的布局.  (软件本身也有 ...

  8. 【转】当你在浏览器地址栏输入一个URL后回车,将会发生的事情?

    http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/ http://www.cnblogs.com/panx ...

  9. js 变量提升和函数提升原理

    关于js的变量,开始的时候我们都会被告知,变量声明应该在引用该变量之前.关于为什么要这样做呢,开始的时候本着会用就行的目的,也没去深究.不过后来经常会发现一些让人很费解的..姑且称为现象吧.先看一段代 ...

  10. iOS 应用中有页面加载gif动画,从后台进入前台时就消失了

    解决办法: 在Appdelegate.m 里面有一个从后台进入前台所响应的方法,可以在该方法里post 一个通知,在加载动画里的页面接受通知,响应一定的方法即可 #pragma -mark 当程序进入 ...