在HTML頁面中加載腳本時,你需要小心,以避免影響頁面的加載性能。根據你在HTML頁面中添加腳本的位置和方式,將影響加載時間。

在HTML頁面中加載腳本時,你需要小心,以避免影響頁面的加載性能。

傳統上,腳本是以以下方式包含在頁面中:

<script src="script.js"></script>

當HTML解析器找到這行代碼時,將發出請求以獲取腳本並執行它。

一旦此過程完成,解析可以繼續,並分析頁面的其餘內容。

正如你可以想像的,此操作對頁面的加載時間產生了巨大影響。

如果腳本加載時間比預期的要長,例如如果網絡速度較慢,或者如果你使用的是移動設備且連接不穩定,訪問者可能會看到一個空白頁面,直到腳本加載並執行完成。

位置的重要性

當你初學HTML時,你被告知腳本標籤位於<head>標籤中:

<html>
 <head>
 <title>標題</title>
 <script src="script.js"></script>
 </head>
 <body>
 ...
 </body>
</html>

正如之前所說,當解析器找到這行代碼時,它將獲取腳本並執行它。 然後,在完成這個任務之後,它繼續解析body。

這樣做是不好的,因為會引入很多延遲。解決這個問題的一個常見解決方案是將script標籤放在頁面底部,即在結束的</body>標籤之前。

這樣做可以在頁面已經解析和加載完成之後加載和執行腳本,這對於不支持HTML的兩個相對新的功能(asyncdefer)的舊瀏覽器來說是一個巨大的改進

如果你需要支持不支持asyncdefer的舊瀏覽器,這是你可以做的最好的事情。

async和defer

asyncdefer都是布爾屬性。它們的使用方式類似:

<script async src="script.js"></script>
<script defer src="script.js"></script>

如果你同時指定了這兩個屬性,對於現代瀏覽器來說,async的優先級更高,而對於支持defer但不支持async的舊瀏覽器,則會回退到使用defer

有關支持情況的詳細信息,可以參考 caniuse.com 中的 async https://caniuse.com/#feat=script-async 和 defer https://caniuse.com/#feat=script-defer

只有在將腳本放在頁面的head部分時,這些屬性才有意義,如果將腳本放在上面看到的body底部,則這些屬性將無效。

性能比較

沒有defer或async,在head中

以下是一個在head部分中未使用defer或async的腳本加載方式:

沒有defer或async,在head中

解析過程在獲取腳本並執行之前暫停,腳本執行完成後解析繼續。

沒有defer或async,在body中

以下是一個在body標籤結束之前並未使用defer或async的腳本加載方式:

沒有defer或async,在body中

解析過程不會暫停,並且腳本在解析完成之後被獲取並執行。解析在腳本甚至下載之前完成,因此頁面在之前的示例中更早地顯示給用戶。

使用async,在head中

以下是一個在head標籤中使用async的腳本加載方式:

使用async

腳本異步獲取,當腳本準備好時,HTML解析將暫停以執行腳本,然後繼續解析。

使用defer,在head中

以下是一個在head標籤中使用defer的腳本加載方式:

使用defer

腳本異步獲取,並且僅在HTML解析完成後才執行。

解析完成的方式與將腳本放在body標籤結束時相同,但是腳本執行的時間總體上更早,因為腳本已經在HTML解析期間並行下載。

因此,就速度而言,這是最好的解決方案🏆

阻塞解析

async會阻塞頁面的解析,而defer則不會。

阻塞渲染

無論是async還是defer都不能保證阻塞渲染。這取決於你的腳本和你的腳本是否阻塞渲染(例如,確保你的腳本在onLoad事件之後運行)。

domInteractive

標記為defer的腳本在domInteractive事件之後執行,該事件在頁面加載、解析並構建DOM之後發生。

此時,CSS和圖像仍需解析並加載。

一旦完成,瀏覽器將觸發domComplete事件,然後是onLoad事件。

domInteractive很重要,因為其時間被認為是感知加載速度的一個衡量標準。有關詳細信息,請參見MDN文檔:https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming/domInteractive

保持順序

再來考慮defer的情況:標記為async的腳本按照隨機順序執行,一旦它們可用。標記為defer的腳本按照在標記中定義的順序(在HTML中)執行。

告訴我最好的方法

在使用腳本時,為了加快頁面加載速度,最好將它們放在head中,並在script標籤中添加defer屬性:

<script defer src="script.js"></script>

這是觸發更快的domInteractive事件的情景。

考慮到defer的優點,它在各種情境下似乎是一個更好的選擇,除非你可以接受延遲頁面的首次渲染,確保在解析頁面時,你希望執行的JavaScript已經執行。