高性能javascript笔记:关于脚本的优化
脚本的阻塞特性:把脚本放在底部
<script>标签因脚本的加载,解析,运行而暂时整个页面的下载和解析过程。如果把它放在<head>标签里面。通常表现为:页面打开时,首先显示为一副空白的页面。
因为脚本阻塞其他页面资源的下载,所以推荐的方法就是:将所有的<script>标签放在尽可能接近<body>标签底部的位置即</body>之前。尽量减少对整个页面下载的影响。
减少脚本的数量
当页面解析每碰到一个<script>时,紧接着都会有一段时间用于js代码的运行,最小化这些延迟时间可以改善页面的性能。另外,对于外部js文件,会发出http请求,每个http请求都会产生额外的性能,下载一个100k的js文件要比下载4个25k的js文件要快,所以合并js有助于改善页面的性能。
精简js源代码及压缩脚本(gzip)
精简js源代码是指去除一个js文件中一切与运行无关的内容,包括注释和不必要的空格,使js源文件体积更小,下载更快。推荐使用JSMin和Dojo Compressor;压缩脚本需要在服务器做相应的配置,同样适用于样式表。
非阻塞加载脚本
非阻塞加载脚本是等页面加载完后再加载Javascript源码。从技术角度来说,这意味着在window的load事件发出后开始下载脚本。
延迟脚本:HTML4为<script>添加了一个defer属性,这个属性指明该脚本不会修改DOM,所以代码可以稍后执行。仅IE和FF3.5支持,其他浏览器依然阻塞。代码如下
<script type="text/javascript" src="file.js" defer="defer"></script>
任何支持带有defer属性的<script>元素在DOM加载完之前是不会被执行的,不管是内联脚本还是外部文件,所以它可以放到页面的任何位置。
动态添加脚本元素:<script>元素与其它元素一样,可以通过Javascript从文档中添加,移动,删除。代码如下
1 var script = document.createElement("script"); 2 script.type = "text/javascript"; 3 script.onload=function(){ 4 //表示已经加载完 5 }; 6 script.src = "file.js"; 7 document.getElementsByTagName("head")[0].appendChild(script);
file.js文件当元素添加到页面后立刻开始下载,重点在于无论在何处启动下载,文件的下载和运行都不会阻塞其他页面资源的处理。因为可能要经常使用到,所以可以封装成一个跨浏览器的函数,方便以后使用:
1 function asyncLoadScript(url,callback){ 2 var script = document.createElement("script"); 3 script.type = "text/javascript"; 4 if(script.readyState){//ie 5 script.onreadystatechange = function(){ 6 if(script.readyState == "loaded" || script.readyState == "complete"){ 7 script.onreadystatechange = null; 8 callback(); 9 } 10 } 11 }else{//other 12 script.onload = function(){ 13 callback(); 14 }; 15 } 16 script.src = url; 17 document.body.appendChild(script); 18 } 19 //加载多个js,保证其顺序 20 asyncLoadScript("file1.js",function(){ 21 asyncLoadScript("file2.js",function(){ 22 asyncLoadScript("file3.js",function(){ 23 //所有js加载完成 24 }); 25 }); 26 });
还有一种方法就是利用XMLHttpRequest对象异步加载js文件,此方法的优点是:在js文件加载完后才创建script元素,所以它下载后不会自动执行。缺点是js文件必须与页面放在同一个域内,不能从CDN(内容分发网络)下载,一般来说大型网站不会使用这种方法。代码如下:
1 //跨浏览器创建XHR对象 2 function createXHR(){ 3 if(typeof XMLHttpRequest != "undefined"){ 4 createXHR = function(){ 5 return new XMLHttpRequest(); 6 }; 7 }else if(typeof ActiveXObject != "undefined"){ 8 createXHR = function(){ 9 if(typeof arguments.callee.activeXString != "string"){ 10 var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"]; 11 for(var i=0; i<versions.length; i++){ 12 try{ 13 var xhr = new ActiveXObject(versions[i]);//试探浏览器支持能力 14 arguments.callee.activeXString = versions[i];//把浏览器支持的XHR版本保存在activeXString属性中 15 return xhr; 16 } 17 catch(ex){ 18 //skip 19 } 20 } 21 } 22 return new ActiveXObject(arguments.callee.activeXString); 23 }; 24 }else{ 25 createXHR = function(){ 26 throw new Error("No XMLHttpRequest object available."); 27 }; 28 } 29 return createXHR(); 30 } 31 //利用XHR对象异步加载JS 32 function XHRLoadScript(url,callback){ 33 var xhr = createXHR(); 34 //为保持跨浏览器兼容性,必须在调用open()之前指定onreadystatechange事件处理程序 35 xhr.onreadystatechange = function(){ 36 if(xhr.readyState == 4){ 37 if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ 38 var script = document.createElement("script"); 39 script.type = "text/javascript"; 40 script.text = xhr.responseText; 41 document.body.appendChild(script); 42 43 callback(); 44 } 45 } 46 }; 47 xhr.open("get",url,true); 48 //尽管不发送数据,但对于某些浏览器来说这个参数是必需的 49 xhr.send(null); 50 51 }
使用其它库来加载js:
1、Yahoo Search的lazyload 用法: LazyLoad.js([urlString|urlArray],function(){});
2、Kyle Simpson的LABjs 用法:$LAB.script(firstURL).script(secondURL).wait(function(){});