html引用js - javascript超連結語法
我應該在HTML標記中放置<script>標記? (14)
在HTML文檔的末尾
這樣在執行時就不會影響瀏覽器中HTML文檔的加載。
將JavaScript嵌入到HTML文檔中時,放置<script>
標記和包含JavaScript的適當位置在哪裡? 我似乎還記得,你不應該把它們放在<head>
部分,但是放在<body>
部分的開頭也是不好的,因為在頁面完全呈現之前必須解析JavaScript(或類似的東西)。 這似乎將<body>
部分的末尾作為<script>
標記的邏輯位置。
那麼,放置<script>
標籤的正確位置在哪裡?
(這個問題引用了這個問題 ,其中建議JavaScript函數調用應該從<a>
標記移動到<script>
標記。我特別使用jQuery,但更通用的答案也是合適的。)
以下是當瀏覽器加載帶有<script>
標籤的網站時發生的情況:
- 獲取HTML頁面(例如index.html)
- 開始解析HTML
- 解析器遇到引用外部腳本文件的
<script>
標籤。 - 瀏覽器請求腳本文件。 同時,解析器會阻止並解析頁面上的其他HTML。
- 經過一段時間腳本被下載並隨後執行。
- 解析器繼續解析HTML文檔的其餘部分。
第4步導致不良的用戶體驗。 您的網站基本上停止加載,直到您下載所有腳本。 如果有一件事讓用戶討厭它正在等待網站加載。
為什麼這會發生?
任何腳本都可以通過document.write()
或其他DOM操作插入自己的HTML。 這意味著解析器必須等到腳本被下載並執行後才能安全地解析文檔的其餘部分。 畢竟,該腳本可能已經在文檔中插入了自己的HTML。
但是,大多數JavaScript開發人員在文檔加載時不再操作DOM。 相反,他們會等到文檔被加載後再修改它。 例如:
<!-- index.html -->
<html>
<head>
<title>My Page</title>
<script type="text/javascript" src="my-script.js"></script>
</head>
<body>
<div id="user-greeting">Welcome back, user</div>
</body>
</html>
使用Javascript:
// my-script.js
document.addEventListener("DOMContentLoaded", function() {
// this function runs when the DOM is ready, i.e. when the document has been parsed
document.getElementById("user-greeting").textContent = "Welcome back, Bart";
});
因為你的瀏覽器不知道my-script.js在下載並執行之前不會修改文檔,解析器會停止解析。
陳舊的建議
解決此問題的舊方法是將<script>
標記放在<body>
的底部,因為這可確保解析器在最後才會被阻止。
這種方法有其自身的問題:在整個文檔被解析之前,瀏覽器不能開始下載腳本。 對於大型腳本和样式表的大型網站,能夠盡快下載腳本對於性能非常重要。 如果您的網站在2秒內未加載,用戶將轉到其他網站。
在最佳解決方案中,瀏覽器將盡快下載腳本,同時解析文檔的其餘部分。
現代的方法
今天,瀏覽器支持腳本的async
和defer
屬性。 這些屬性告訴瀏覽器在下載腳本時繼續解析是安全的。
異步
<script type="text/javascript" src="path/to/script1.js" async></script>
<script type="text/javascript" src="path/to/script2.js" async></script>
具有異步屬性的腳本異步執行。 這意味著腳本在下載後立即執行,同時不會阻止瀏覽器。
這意味著腳本2可以在腳本1之前下載並執行。
根據http://caniuse.com/#feat=script-async的瀏覽器都支持這一點。
延緩
<script type="text/javascript" src="path/to/script1.js" defer></script>
<script type="text/javascript" src="path/to/script2.js" defer></script>
具有defer屬性的腳本按順序執行(即第一個腳本1,然後是腳本2)。 這也不會阻止瀏覽器。
與異步腳本不同,延遲腳本僅在整個文檔被加載後執行。
根據http://caniuse.com/#feat=script-defer ,所有瀏覽器的90%都支持這一點。 92%至少部分支持它。
關於瀏覽器兼容性的一個重要注意事項:在某些情況下,IE <= 9可能會按順序執行延遲腳本。 如果您需要支持這些瀏覽器,請先閱讀this !
結論
目前最先進的技術是將腳本放在<head>
標籤中,並使用async
或defer
屬性。 這可以讓您的腳本盡快下載,而不會阻塞您的瀏覽器。
好處是你的網站仍然應該在不支持這些屬性的20%瀏覽器上正確加載,而加速其他80%。
傳統的(並且被廣泛接受的)答案是“處於最底層”,因為然後在任何事情能夠開始執行之前整個DOM將被加載。
有各種各樣的原因,從可用的實踐開始,故意開始執行頁面加載事件。
取決於,如果你正在加載一個腳本來設置你的頁面風格/在你的頁面中使用動作(比如點擊一個按鈕),那麼你最好把它放在頂部。 如果你的樣式是100%CSS,並且你有所有按鈕動作的後備選項,那麼你可以把它放在底部。
或者最好的東西(如果這不是問題),您可以製作一個模式加載框,將您的JavaScript放在頁面底部,並在腳本的最後一行加載時使其消失。 這樣可以避免用戶在加載腳本之前使用頁面中的操作。 同時也避免了不恰當的造型。
如果您正在使用JQuery,請將javascript放在最適合的位置,並使用$(document).ready()
來確保在執行任何函數之前正確加載了內容。
在旁注中:我喜歡<head>
部分中的所有腳本標記,因為它似乎是最乾淨的地方。
您可以將<script>
引用的大部分放在<body>
的末尾,
但是,如果頁面上有使用外部腳本的活動組件,
那麼他們的依賴(js文件)應該在此之前(最好在頭標籤中)。
最後包含腳本主要用於首先顯示網站內容/樣式的地方。
包括頭部的腳本儘早加載腳本,並且可以在加載整個網站之前使用腳本。
如果最後輸入腳本,則只有在加載完整樣式和設計後才能進行驗證,而快速響應的網站則不會加以欣賞。
根據腳本及其用法,盡可能最好(就頁面加載和渲染時間而言)可能不是使用傳統的<script> -tag本身,而是動態地觸發異步加載腳本。
有一些不同的技術,但最直接的方法是在觸發window.onload事件時使用document.createElement(“腳本”)。 然後,腳本首先在頁面本身渲染時加載,因此不會影響用戶等待頁面顯示的時間。
這自然要求腳本本身不需要渲染頁面。
有關更多信息,請參閱Steve Souders(YSlow的創建者,但現在位於Google)的Coupling異步腳本 。
正如前面所述,在結束標籤之前
http://developer.yahoo.com/performance/rules.html#js_bottom
將腳本放在底部
腳本導致的問題是它們會阻止並行下載。 HTTP / 1.1規范建議瀏覽器每個主機名並行下載至少兩個組件。 如果您從多個主機名提供圖像,則可以同時發生兩個以上的下載。 然而,當腳本正在下載時,瀏覽器將不會啟動任何其他下載,即使是在不同的主機名上。
編寫JavaScript
代碼到文檔代碼後面加載文檔然後執行js代碼的最佳位置。 如果你寫JQuery
代碼寫
$(document).ready (function{
//your code here
});
腳本塊加載DOM,直到它被加載並執行。
如果你把腳本放在<body>
的最後,所有的DOM都有機會加載和渲染(頁面將“更快地顯示”)。 <script>
將有權訪問所有這些DOM元素。
另一方面,將它放在<body>
開始或之後將執行腳本(仍然沒有DOM元素)。
你正在使用jQuery,這意味著你可以將它放在任何你想使用的地方.ready()
非阻塞腳本標籤可以放在任何地方:
<script src="script.js" async></script>
<script src="script.js" defer></script>
<script src="script.js" async defer></script>
這些腳本將在文檔準備好後異步執行,這意味著您不能這樣做:
<script src="jquery.js" async></script>
<script>jQuery(something);</script>
<!--
* might throw "jQuery is not defined" error
* defer will not work either
-->
或這個:
<script src="document.write(something).js" async></script>
<!--
* might issue "cannot write into document from an asynchronous script" warning
* defer will not work either
-->
或這個:
<script src="jquery.js" async></script>
<script src="jQuery(something).js" async></script>
<!--
* might throw "jQuery is not defined" error (no guarantee which script runs first)
* defer will work in sane browsers
-->
或這個:
<script src="document.getElementById(header).js" async></script>
<div id="header"></div>
<!--
* might not locate #header (script could fire before parser looks at the next line)
* defer will work in sane browsers
-->
話雖如此,異步腳本提供了這些優點:
- 並行下載資源 :
瀏覽器可以並行下載樣式表,圖像和其他腳本,無需等待腳本下載和執行。 - 來源訂單獨立性 :
您可以將腳本放置在頭部或身體中,而無需擔心阻塞(如果使用CMS,則可用)。 執行順序依然很重要。
通過使用支持回調的外部腳本可以規避執行順序問題。 許多第三方JavaScript API現在支持非阻塞執行。 以下是異步加載Google Maps API的示例。
<script src="myjs.js"></script>
</body>
腳本標籤應該始終在body關閉之前使用,或者在HTML文件中使用Bottom 。
那麼你可以在加載js文件之前先看到頁面的內容。
檢查這是否需要: http://stevesouders.com/hpws/rule-js-bottom.php : http://stevesouders.com/hpws/rule-js-bottom.php
如果您仍然關心IE <10中的支持和性能,最好總是讓您的腳本標記HTML body的最後一個標籤。 這樣,你就可以確定DOM的其他部分已經被加載,你不會阻塞和渲染。
如果您對IE <10不再太在意,您可能希望將腳本放在文檔的頭部,並使用
defer
來確保它們僅在DOM加載後運行(<script type="text/javascript" src="path/to/script1.js" defer></script>
)。 如果你仍然希望你的代碼在IE 10中工作,不要忘記把你的代碼封裝在window.onload
,儘管!