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输出如下:
Thanks, great article.