指令碼的阻塞特性:把指令碼放在底部
<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{//other12 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 //skip19 }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對象非同步載入JS32 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(){});