指令碼可以放在html頁面的head裡面,也可以放在body裡面。
把指令碼放在body中,當瀏覽器遇見<script>標籤時, 瀏覽器不知道指令碼會插入文本還是html標籤,因此瀏覽器會停止分析html頁面而去執行指令碼。當使用src的方式添加指令碼時,瀏覽器也會做同樣的動作。在指令碼處理的時候,頁面呈現和使用者互動將被完全阻止。指令碼下載和執行阻塞了其他資源的下載,比如呈現頁面使用的圖片。(雖然很多瀏覽器實現了指令碼並行下載的技術,但是這個問題依然沒有解決)
指令碼的位置
鑒於上面的理由,指令碼應該始終放在頁面的底部,即</body>前面。
一個簡單的樣本:
複製代碼 代碼如下:<html>
<head>
<title>Script Example</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<p>Hello world!</p>
<script type="text/javascript" src="file1.js"></script>
<script type="text/javascript" src="file2.js"></script>
<script type="text/javascript" src="file3.js"></script>
</body>
</html>
合并指令碼
因為指令碼下載阻塞了頁面呈現,因而應該減少頁面<script>標籤的使用,不管指令碼是內聯的還是外部的。在處理外部指令碼的時候情況比較特殊,瀏覽器下載一個100kb的指令碼的時間將遠遠小於4個25kb的指令碼,因為建立一個請求要消耗大量的時間。所以頁面應該盡量的減少外部指令碼的引用。
非阻塞的指令碼
秘訣在於當頁面loading完成之後再來載入指令碼,也就是在window對象的onload事件觸發之前 。下面是實現的幾種方式:
1.使用defer 複製代碼 代碼如下:<html>
<head>
<title>Script Defer Example</title>
</head>
<body>
<script defer>
alert("defer");
</script>
<script>
alert("script");
</script>
<script>
window.onload = function(){
alert("load");
};
</script>
</body>
</html>
頁面彈出框出現的順序: script/defer/load,這個技術的缺點是IE4+和FF3.5+才支援。
非阻塞的指令碼(續)
2. 動態指令碼元素
要知道<script>和普通的html標籤並沒有本質的區別,所以可以利用標準的DOM方法動態添加指令檔引用。方法如下: 複製代碼 代碼如下:var script = document.createElement("script");
script.type = "text/javascript";
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
當這個標籤一旦加入到html中,指令檔就開始下載。這種方法的一個特點就是,檔案下載和執行並不阻塞html頁面其它部分的處理。通常將這樣的指令碼放在<head>中較之<body>更加安全,尤其是檔案包含的代碼需要在頁面的load事件中執行。如果body的內容還沒有被完全的載入,IE還會彈出“禁止操作”的錯誤。
當指令檔下載完成之後,指令碼立即執行(FF、Opera會等待前一個以同樣方式添加的指令碼執行)。當指令碼自執行時,這沒什麼問題。但是如果指令碼包含頁面中其它指令碼使用的interfaces,你需要確認指令碼已經載入完成並且可用。幸好,當獲得script標籤的src的值之後,Firefox, Opera, Chrome, and Safari 3+ 會觸發一個load事件。 複製代碼 代碼如下:var script = document.createElement("script")
script.type = "text/javascript";
//Firefox, Opera, Chrome, Safari 3+
script.onload = function(){
alert("Script loaded!");
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
IE則提供了另外一種解決方案--readystatechange事件。根據下載
指令檔所處的狀態,readyState 的值有以下幾種:
"uninitialized"
預設狀態
"loading"
開始下載
"loaded"
下載完成
"interactive"
下載完成,但是並非全部可用
"complete"
所有資料可用
IE的實現方式: 複製代碼 代碼如下:var script = document.createElement("script")
script.type = "text/javascript";
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
alert("Script loaded.");
}
};
script.src = "file1.js";
document.getElementsByTagName("head")[0].appendChild(script);
下面是綜合以後的通用方法: 複製代碼 代碼如下:function loadScript(url, callback){
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 { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
The loadScript() function is used as follows:
loadScript("file1.js", function(){
alert("File is loaded!");
});
現在你可以按這種動態方式載入指令碼了,但是你仍然需要考慮這些檔案的下載順序。主流瀏覽器中只有FF和Opera保證指令碼的執行順序和你指定的下載順序一致,其他瀏覽器將按照指令檔從伺服器返回的順序來執行。雖然如此,我們仍然有替代的解決方案: 複製代碼 代碼如下:loadScript("file1.js", function(){
loadScript("file2.js", function(){
loadScript("file3.js", function(){
alert("All files are loaded!");
});
});
});
這樣我們就能保證指令檔的下載順序嚴格的按照file1-file2-file3的方式進行。
註明:以上內容來自:<High Performance JavaScript>by Nicholas C. Zakas