JavaScript <script>標簽的位置、延遲腳本(defer屬性)與 異步腳本(async屬性)
一、<script>標簽的位置
傳統的做法是將<script>元素放在<head>元素中,例如:
<!DOCTYPE html><html > <head> <title>Example</title> <script type="text/javascript" src="example.js"></script> </head> <body> <!--這裏放內容--> </body> </html>
但是這種做法有一個問題,在文檔的<head>元素中包含所有JavaScript文件,意味著必須等到全部JavaSeript代碼都被下載、解析和執行完成以後,才能開始呈現頁面的內容(瀏覽器在遇到<body>標簽時才開始呈現內容)
<!DOCTYPE html><html > <head> <title>Example</title> </head> <body> <!--這裏放內容--> <script type="text/javascript"src="example.js"></script> </body> </html>
這樣,在解析包含的JavaScript代碼之前,頁面的內容就已經完全呈現在瀏覽器中了。而用戶也會因為瀏覽器窗口顯示空白頁面的時間縮短而感覺打開頁面的速度加快了。
二、延遲腳本(defer屬性)
只適用於外部腳本文件
HTML 4.01為<script>標簽定義了defer屬性。這個屬性的用途是表明腳本在執行時不會能響頁面的構造。也就是說,腳本會被延遲到整個頁面都解析完畢後再運行。因此,在<script>元素中設置defer屬性,相當於告訴瀏覽器立即下載,但延遲執行
<!DOCTYPE html> <html> <head> <title>Example</title> <script type="text/javascript" defer="defer" src="example1.js"></script> <script type="text/javascript" defer="defer" src="example2.js"></script> </head> <body> <!-- 這裏放內容 --> </body> </html>
在這個例子中,雖然把<script>元素放在了文檔的<head>元素中,但其中包含的腳本將延遲到瀏覽器遇到</html>標簽後再執行。HTML5規範要求腳本按照它們出現的先後順序執行,因此第一個延遲腳本會先於第一個延遲腳本執行, 而這兩個腳本會先於DOMContentLoaded 事件執行。但在現實當中,延遲腳本並不一定會按照順序執行也不一定會在DOMContentLoaded事件觸發前執行,因此最好只包含一個延遲腳本。
IE4、Firefox 3.5、Safari 5和Chrome是最早支持defer屬性的瀏覽器。其他瀏覽器會忽略這個屬性,像平常樣處理腳本。為此,把延遲腳本放在頁面底部仍然是最佳選擇。
三、異步腳本(async屬性)
只適用於外部腳本文件
HTML5為<script>元素定義了async屬性。這個屬性與defer屬性類似,都用於改變腳本的行為,並告訴瀏覽器立即下載文件。但與defer不同的是,標記為async的腳本並不保證按照指定它們的先後順序執行。例如:
<!DOCTYPE html> <html> <head> <title>Example</title> <script type="text/javascript" async src= "example1.js"></script> <script type="text/javascript" async src= "example2.js"></script> </head> <body> <!--這裏放內容--> </body> </html>
在以上代碼中,第二個腳本文件可能會在第一個腳本文件之前執行。因此,確保兩者之間互不依賴非常重要。指定async屬性的目的是不讓頁面等待腳本下載和執行,從而異步加載頁面其他內容。為此,建議異步腳本不要在加載期間修改DOM。
四、需要註意的小知識點
1、帶有src屬性的<script>元素不應該在其<script>和</script>標簽之間再包含額外的JavaScript代碼。如果包含了嵌入的代碼,則只會下載並執行外部腳本文件,嵌入的代碼會被忽略。
2、無論如何包含代碼,只要不存在defer和async屬性,瀏覽器都會按照<script>元素在頁面中出現的先後順序對它們依次進行解析。換句話說,在第一個<script>元素包含的代碼解析完成後,第三個<script>包含的代碼才會被解析,然後才是第三個、第四個.....
JavaScript <script>標簽的位置、延遲腳本(defer屬性)與 異步腳本(async屬性)