script标签有两个和性能、js文件下载执行相关的属性:defer和async,defer是HTML4中就有的属性,async是HTML5中新有的属性。

defer – html代码

<script defer src=”myscript.js” onload=”myInit()”></script>

async – html代码

<script async src=”myscript.js” onload=”myInit()”></script>

 

它们的区别是什么?

带有defer或者async的script都会立刻下载并不阻塞页面解析,而且都提供一个可选的onload事件处理,在script下载完成后调用,用于做一些和此script相关的初始化工作。它们的不同之处在于script执行的时机,带有async的script,一旦下载完成就立即执行(在window的onload之前)。这意味着这些带有async的script可能不会按它们出现在页面中的顺序来执行,如果脚本互相依赖并和执行顺序相关,就有很大的可能出现问题, 例如变量或者函数未定义之类的错误;而对于带有defer的script,它们会确保按在页面中出现的顺序来执行,它们执行的时机是在页面解析完后,但在 DOMContentLoaded事件之前。

目前哪些浏览器支持defer和async?

目前来看,firefox、chrome和safari都支持这两个属性,也都支持script的load事件。IE对defer是一直都支持的,async属性IE6~9都不支持,onload属性是在IE9中新加入的属性。

—-下面是对defer,async,onload的测试用例—-

写了简单的四段脚本用于测试

/** script1 **/
window.ns = {};
window.ns.delay = function(n) {
var start = Number(new Date()),
wait = n * 1000;
while(true) {
var end = Number(new Date());
if(end-start >= wait) {
break;
}
}
console.log(“take ” + n + ” seconds to execute”);
};
console.log(“create a namespace named ns”);
document.addEventListener(“DOMContentLoaded”, function() {
console.log(“oh yeah, Dom Ready!”);
}, false);
window.addEventListener(“load”, function() {
console.log(“oh yeah, All Resources Loaded!”);
}, false);

/** script2 **/
if(window.ns) {
window.ns.one = ‘ONE’;
console.log(‘window.ns.one:’ + window.ns.one);
window.ns.delay(2);
} else {
console.log(‘oops…’);
}

/** script3 **/
if(window.ns && window.ns.one) {
window.ns.two = “TWO”;
console.log(‘window.ns.two:’ + window.ns.two);
window.ns.delay(2);
} else {
console.log(‘oops…’);
}

/** script4 **/
if(window.ns && window.ns.two) {
window.ns.three = “THREE”;
console.log(‘window.ns.three:’ + window.ns.three);
} else {
console.log(‘oops…’);
}

用于测试的html页面

<!DOCTYPE htm>
<html>
<head>
  <meta charset=”utf-8″>
  <title>test</title>
  <script type=”text/javascript” src=”script1.js”></script>
  <script type=”text/javascript” src=”script2.js”></script>
  <script type=”text/javascript” src=”script3.js”></script>
  <script type=”text/javascript” src=”script4.js”></script>
</head>
<body>
  <img src=”http://img9.zol.com.cn/desk_pic/big_452/451134.jpg”
  width=”200″ height=”200″ alt=”a big image of beauty”/>
</body>
</html>

接下来就是在script上加上defer和async进行测试

1.无defer和async属性

<script type=”text/javascript” src=”script1.js”></script>
<script type=”text/javascript” src=”script2.js”></script>
<script type=”text/javascript” src=”script3.js”></script>
<script type=”text/javascript” src=”script4.js”></script>

我们先看资源加载瀑布图(firefox和chrome类似,IE9的有点奇怪):

看得出来,image的下载被script的执行给阻塞了。

console输出如下:

2.都带上defer属性

<script type=”text/javascript” src=”script1.js” defer></script>
<script type=”text/javascript” src=”script2.js” defer></script>
<script type=”text/javascript” src=”script3.js” defer></script>
<script type=”text/javascript” src=”script4.js” defer></script>

资源加载瀑布图:

看得出来,所有资源进行了并行下载,没有阻塞img的情况

console输出和第1个测试的输出一致,IE9和chrome是如此,但是奇怪的是Firefox在这种情况下,居然没有触发DOMContentLoaded事件,即输出少了Dom Ready!一行

3.部分带上defer属性

<script type=”text/javascript” src=”script1.js”></script>
<script type=”text/javascript” src=”script2.js” defer></script>
<script type=”text/javascript” src=”script3.js” ></script>
<script type=”text/javascript” src=”script4.js” defer></script>

因为这里面4个script都是有执行顺序依赖的,所以如果defer属性不加选择的添加的话,就会出问题,本例中script1和script3就会先执行,script2和script4晚执行,就出现错误了。

console输出如下:

4.都带上async属性

<script type=”text/javascript” src=”script1.js” async></script>
<script type=”text/javascript” src=”script2.js” async></script>
<script type=”text/javascript” src=”script3.js” async></script>
<script type=”text/javascript” src=”script4.js” async></script>

IE9不支持这个属性,所以不用测试。Firefox和chrome都是第一次访问时,出现了异步执行的情况,之后有缓存的话,script的执行顺序貌似得到了维护。资源时间瀑布上表现出的是预期的情况,即没有给其他资源的下载造成阻塞。

Chrome中第一次访问,console输出如下,无论出错与否,chrome和firefox的DOMContentLoaded均未被触发

5.部分给async属性

<script type=”text/javascript” src=”script1.js” async></script>
<script type=”text/javascript” src=”script2.js”></script>
<script type=”text/javascript” src=”script3.js”></script>
<script type=”text/javascript” src=”script4.js” async></script>

这种情况的效果,在chrome下比较明显,分析起来也很简单,4个script都是并行下载,但是如果script1和script4下完后立马执行,很显然就破环了它们之间的依赖关系,可惜的是这种竞争的现象在Firefox中出现的概率比较低,可能跟firefox的缓存机制有关系。

chrome的console输出如下: