《高性能javascript》读书笔记:第一章 加载和执行
因为:在一个html页面中,当有<script>标签时,无论是内嵌的还是外链的,都会阻塞页面的下载和渲染。
所以:尽量将<script>标签放到<body>标签的底部。
因为:每一个<script>标签初始化下载时都会阻塞页面渲染, 并且每一个<script>下载完后的执行也需要一定的延时。不仅仅是外链脚本,内嵌脚本也一样。
并且多个外链脚本会增加http请求数量影响性能。
所以: 尽量减少<script>的个数
因为:把一段内嵌脚本放在引用外链样式表<link>标签之后会导致页面阻塞去等待样式表的下载,这样做是为了确保内嵌脚本在执行时能获得最精确的样式信息。
所以:永远不要把内嵌脚本紧跟在<link>标签后面
多个外链的脚本应该通过离线打包工具或类似Yahoo!combo handler的实时的在线服务来实现。
无阻塞脚本的秘诀在于,在页面加载完成后才加载javascript代码。也就是说在windows对象的load事件触发后再下载脚本。几种方式:
1,用扩展属性:defer
defer指明了脚本不会修改dom,因此代码能安全地延迟执行,下载和执行都不会阻塞页面渲染。
示例:
<script type="text/javascript" src="file1.js" defer></script>
或
alert("晚于没有defer标记的脚本执行,早于window.onload执行");
</script>
缺点:只有IE4+和Firefox3.5+支持
2,动态脚本元素:通过DOM(文档对象模型) 可以用javascript动态创建包括<script>标签在内的所有元素。
示例:
script.type="text/javascript";
script.src="file1.js";
document.getElementByTagName("head")[0].appendChild(script);//此处是加到head
使用此种方式下载文件时,返回的代码会立即执行(firefox和opera会等待此前所有动态脚本节点执行完毕)。
firefox,opera,chrome和safari3以上版本会在<script>元素接收完成时触发一个load事件:
示例: script.onload=function(){alert("接收完成");};
IE会触发一个readystatechange事件,<script>元素提供readystate属性(uninitialized:初始状态 ,loading:开始下载,loaded:下载完成,interactive:数据完成下载但尚不可用,complete:所有数据已准备就续)
示例:
if(script.readystate="loaded"||script.readystate=="complete"){ //一般只要判断这两种情况
script.onreadystatechange=null; //这里必须删除事件,以确保事件不会处理两次
alert("接收完成");
}
};
这里提供一个供标准及IE共用的方法
var script=document.createElement("script");
script.type="text/javascript";
if(script.readystate){//IE
script.onreadystatechange=function(){
if(script.readyState=="loaded"||script.readyState== “complete"){
script.onreadystatechange=null;
callback();
}
};
}else{//其它浏览器
script.onload=function(){
callback();
};
}
script.src=url;
document.getElementsByTagName("head")[0].appendChild(script);
}
使用时直接调用就可以了
alert("加载完成");
});
或者串联起来按顺序下载多个
loadScript("file2.js",function(){
alert("加载完成");
});
});
3,XMLHttpRequest脚本注入:发送一个get请求,然后把获取到的响应作为script的内容,再用DOM加到head中。
这个的缺点是不能请求跨域的js文件,所以通常不用它。
4,推荐的无阻塞模式
A,用上面所述的动态loadScript方法加载界面渲染必须的脚本,在加载完成的事件里再加载其它脚本,并且放在</body>闭合标签之前。建议用YUI Compressor把脚本进行压缩。
B,LazyLoad类库 http://github.com/rgrove/lazyload 1.5K
示例:
<script type="text/javascript">
LazyLoad.js(["file1.js","file2.js"],function(){ //如果只加载一个文件的话不需要中括号
Application.init();
});
</script>
C,LABjs类库 http://labjs.com
示例:
<script type="text/javascript">
$LAB.script("file1.js").wait() //用这个wait能保证先执行完再下载file2.js。下面的file2.js和file3.js不一定谁先下载
.script("file2.js")
.script("file3.js")
.wait(function(){
Application.init();
});
</script>