欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

无阻塞加载脚本的最佳方案

最佳方案

没有独立的最佳方案,真正的最佳方案取决于需求,选择最佳脚本下载技术的决策树如下:

选择最佳脚本加载技术的决策树

选择最佳脚本加载技术的决策树

在决策树里有6种可能的结果:

  • 不同域、无序

    XHR Eval、XHR注入和Script in Iframe技术在这些情况下无法使用,因为主页面的域与脚本的域不同。我们不应该使用Script Defer技术,因其迫使脚本按顺序加载,相反,如果脚本能一到达就执行的话会让页面加载更快一些。对于这种情况,Script DOM Element技术是最佳方案,但它会导致在Firefox中加载时保持顺序,虽然我们并不希望这样。注意这两种技术都触发忙指示器(状态栏、进度条、图标、光标),但我们没有办法避免这个问题。

    包含JavaScript广告和控件的网页是符合这种情况的实例。广告和控件的脚本所在的域往往和主页面不同,但是它们之间没有任何依赖关系,所以加载顺序无关紧要。

  • 不同域、保持顺序

    和前面一样,因为主页面的域与脚本不同,XHR Eval、XHR注入和Script in Iframe技术行不通。为了确保加载顺序,我们应该在Internet Explorer中使用Script Defer技术,而在Firefox中使用Script DOM Element技术。注意这两种技术都触发忙指示器。

    一个符合这种情况的实例是从不用的服务器下载多个存在依赖关系的JavaScript文件的页面。

  • 同域、无序、无忙指示器

    XHR Eval和XHR注入是唯一不触发忙指示器的两种技术。这两种XHR技术,我更推荐XHR注入,因为使用该技术时脚本无需重构。

    可以应用于希望在后台下载JavaScript文件的网页

  • 同域、无序、有忙指示器

    XHR Eval、XHR注入和Script in Iframe是唯一跨Internet Explorer和Firefox而不保持加载顺序的技术。Script in Iframe技术看起来似乎是最佳选择,因为它触发忙指示器,而且只是稍微增加了一些页面大小。但我更倾向于XHR注入,因为使用该技术时脚本无需重构就能使用,而且它同时是其它决策树分支的选择。我们需要额外的JavaScript来激活忙指示器:当XHR发出时激活状态栏和光标,XHR返回时恢复,我们称之为Managed XHR Injection

  • 同域、保持顺序、无忙指示器

    XHR Eval和XHR注入是两个不触发忙指示器的技术。这两种XHR技术中我更倾向于XHR注入,因为使用该技术时脚本无需重构。为了保持加载顺序,需要另一种类型的Managed XHR Injection。在这种情况下,如有必要,可以把XHR相应塞进队列里,按顺序执行,延迟加载的脚本需要在它之前的所有脚本下载并执行完毕后才开始执行,

    有多个存在内部依赖的脚本在后台下载的页面符合这种情况

  • 同域、保持顺序、有忙指示器

    Internet Explorer中的Script Defer技术和Firefox中的Script DOM Element技术是首选方案。Managed XHR Injection和Managed XHR Eval技术也是可行的。但是她们会给主页面增加额外的代码,而且实现它们更复杂一些。

P.S.以上内容摘自参考资料

XHR Eval

xhr获取脚本str,然后eval(str)执行

优点:无阻塞(不会阻塞其它资源的下载)

缺点:同源策略(Same Origin Policy)限制,外部脚本必须与正在执行的脚本同域(协议、端口号、域名)。此外,外部脚本可能需要重构

XHR注入

xhr获取脚本str,然后把str塞进script元素,再插入DOM树执行

优点:无阻塞

缺点:SOP限制

Script in Iframe

页面中的iframe和其它资源是并行加载的,可以利用这个特点来实现无阻塞加载脚本:

<!-- 在主页面中内包含iframe,jsWrapper.html应该与主页面同域 -->
<iframe src="jsWrapper.html" frameborder="0" width="0" height="0" id="myIframe"></iframe>

//---js通信
// 主页面 -> iframe
var winIframe = window.frames['myIframe'].contentWindow;
winIframe.fun();    // winFrame是iframe中的window对象
// iframe -> 主页面
var winMain = window.parent;
winMain.fun();      // winMain是主页面中的window对象

注意srcx.html而不是x.js,因为iframe认为返回的是html文档,所以应该把脚本用html包装成inline script

优点:无阻塞

缺点:SOP限制,且外部脚本需要重构

Script DOM Element

动态创建script元素设置src并插入DOM树

优点:无阻塞,允许跨域,外部脚本无需重构,能够保证脚本执行顺序

缺点:IE下不能保证脚本执行顺序

Script Defer

IE支持script标签的defer属性,允许其它资源并行下载

优点:容易(给script标签添一个属性就行),而且能够保证脚本执行顺序

缺点:某些浏览器(比如低版本FF)可能不支持该属性,但html5标准已经确定了deferasync的地位,而且新增了onload回调,目前兼容性问题不严重,更多信息请查看HTML5 <script>元素async,defer异步加载

document.write Script Tag

document.writescript标签写入页面

优点:在IE用document.write写入的多个脚本可以并行加载

缺点:只有IE无阻塞,而且在加载这些脚本时,其它资源(图片,DOM)都会被阻塞

参考资料

  • 《高性能网站建设进阶指南》
普通分类: