<script> 的 async 與 defer 有什麼不同?

2023年2月10日

💎 加入 E+ 成長計畫 與超過 300+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

「HTML 的  <script> 當中, <script async>  與  <script defer> 有什麼差別?」這一題可以分成兩個階段來答,先討論為什麼需要 asyncdefer 這兩個屬性,接著再分析兩者的差別。以下為這題的擬答筆記。

為什麼需要 asyncdefer?

之所以會有 asyncdefer 的出現,是因為瀏覽器在解析 HTML 時,如果遇到 <script> 標籤,就會先停下手邊建構 DOM 的工作,開始載入<script> 的腳本資源,並執行下載好的腳本。直到下載與執行完畢後,才會繼續 DOM 的建構。

這將會造成兩難的局面,如果把 <script> 標籤順序擺比較上面,則可能導致如果腳本比較肥大,要載入比較久,進而導致畫面比較晚才被渲染出來。這是為什麼在過去許多人會把 <script> 標籤放在最下面,然而,如果這麼做,則會導致當渲染完畫面後,還要等 script 的載入與執行,這會讓畫面雖然渲染出來,但是沒辦法有功能。

這是為什麼後來 HTML 在 <script> 標籤當中加入了 asyncdefer 。這兩個屬性都是在跟瀏覽器說,不用等腳本的載入,繼續建構 DOM。這讓 DOM 的建構與腳本的載入能夠同步進行,讓使用者體驗可以更好。

asyncdefer 有什麼不同?

雖然兩者有類似的功能,但 asyncdefer 仍有所不同,也適合用在不同的情境。

defer

defer 會告訴瀏覽器,不用等腳本的下載與執行,可以繼續完成 HTML 的解析與 DOM 的建構;在建構 DOM 的同時,會在背景中載入腳本,因此 defer 不會擋住畫面的渲染。如果腳本在 HTML 解析完成前就下載好,會等到 HTML 都完全解析後,才會執行。因此如果有腳本是需要等 HTML 解析完、DOM 完整建立後才能載入,那麼會需要選 defer

如果同時有多個帶有 defer 屬性的 <script> 資源,瀏覽器會同步下載,只是會依照在 HTML 中的順序執行,這可以確保執行時是依照我們想要的順序。有些時候,可能某個腳本會依賴另一個腳本,例如 A 依賴 B,這時候要確保 A 是在 B 之前執行,這時會選擇用 defer

async

async 的意思是 asynchrnous,意即非同步,換句話說解析 HTML 與載入腳本,是非同步進行。因此,同樣會告訴瀏覽器,在解析 HTML 時不用等 <script> 腳本的下載與執行。但跟 defer 不同的地方在於, async 的腳本載入與 HTML 解析是彼此獨立的,因此只要下載完就會馬上執行,而不是像 defer 會等到 HTML 解析完成才執行。

除了跟 DOM 的建構是彼此獨立之外,帶有 async 屬性的腳本跟其他的腳本也是彼此獨立,哪個先下載完成就先執行。雖然在下載時不會暫停 HMTL 的解析,但在執行時腳本時會暫停解析。通常如果腳本載入跟 DOM、其他腳本是沒有相互依賴關係,例如 Google Analytics 這類分析用的腳本。


相關文章

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們