非阻塞脚本加载

时间 : 14-08-19 评论 : 0 点击 : 1,333 次

前言

script标签是阻塞的。当浏览器遇到script标签,就会停止页面解析,直到script标签被处理完成:1、如果是文件,文件被加载完毕,文件内包含的代码被执行完成。2、如果是代码,代码被执行完成。 如果用多个script标签加载多个js文件,现在主流浏览器均支持多线程并发加载多个js文件,假如有2个script标签先后引入1.js、2.js,浏览器并发发起2个http请求,即使2.js先于1.js加载完成,2.js的代码依然会在1.js的代码执行之后才执行,这一机制保证了代码执行顺序是可预期的。在1.js和2.js代码被执行完成之前,其后的js代码不会被执行、html代码不会被渲染。

古老的defer

使用语法如下:<script type="text/javascript" src="file1.js" defer></script> 对应的JavaScript 文件将在<script>被解析时启动下载,但代码不会被执行,直到DOM 加载完成(在onload 事件句柄被调用之前)。当一个defer的JavaScript 文件被下载时,它不会阻塞浏览器的其他处理过程,所以这些文件可以与页面的其他资源一起并行下载。 任何带有defer 属性的<script>元素在DOM 加载完成之前不会被执行,不论是内联脚本还是外部脚本文件,都是这样。 浏览器的支持:只有IE支持,FF较低版本支持,最新版本不支持,Chrome则从没支持过 浏览器不兼容,不推荐使用

动态脚本元素

动态创建<script>标签插入到html结构中。js文件在元素添加到页面之后立刻开始下载。此技术的重点在于:无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程。可以将这些代码放在<head>部分而不会对其余部分的页面代码造成影响(除了占用一个用于下载文件的HTTP 连接)。 当文件使用动态脚本节点下载时,返回的代码通常立即执行(除了Firefox 和Opera,他们将等待此前的所有动态脚本节点执行完毕)。加载多个脚本时,如果想保证脚本代码的执行顺序,则只能采用加载完毕一个js资源再加载第二个js资源这样一个串行加载方案。

文件加载完成的判断:

主流浏览器在文件加载完成时都会触发onload事件,IE6除外。IE6需要用onreadystatechange事件来判断文件是否加载完成

动态脚本元素的技术方案常见于以下两个场景:

模块化编程,各模块自行负责解决依赖。通常需要动态加载js文件。

跨域的jsonp协议通信

XHR 脚本注入

使用XMLHttpRequest(XHR)对象将脚本注入到页面中。此技术首先创建一个XHR 对象,然后下载JavaScript文件,接着用一个动态<script>元素将JavaScript代码注入页面。这样做实际上会创建一个带有内联代码的<script>标签。一旦新<script>标签被添加到文档,代码将被执行。这个技术方案的好处是下载后不会自动执行代码,你可以自行决定什么时候把代码放入script标签中执行;缺点是不能跨域。

var xhr = new XMLHttpRequest();
xhr.open("get", "file1.js", true);
xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
        if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.text = xhr.responseText;
            document.body.appendChild(script);
        }
    }
};
xhr.send(null);

非阻塞加载相关的开源库

http://github.com/rgrove/lazyload/
LazyLoad可以下载多个JavaScript 文件,并保证它们在所有浏览器上都能够按照先后的顺序执行。要加载多个JavaScript 文件,只要调用LazyLoad.js()函数并传递一个URL 数组给它。

http://labjs.com/
LabJs会用尽可能多的进程下载js,并保证正确的执行顺序。$LAB.script("1js").script("2.js").wait(function(){$LAB.script("2.js").}); 1.js和2.js的先后顺序不重要,可以并行加载和解释执行,3.js必须在1.js和2.js解释执行之后执行。

javascript

非阻塞脚本加载:等您坐沙发呢!

发表评论