<script> 的 async 與 defer 有什麼不同?
2023年2月10日
「HTML 的 <script>
當中, <script async>
與 <script defer>
有什麼差別?」這一題可以分成兩個階段來答,先討論為什麼需要 async
與 defer
這兩個屬性,接著再分析兩者的差別。以下為這題的擬答筆記。
為什麼需要 async
與 defer
?
之所以會有 async
與 defer
的出現,是因為瀏覽器在解析 HTML 時,如果遇到 <script>
標籤,就會先停下手邊建構 DOM 的工作,開始載入<script>
的腳本資源,並執行下載好的腳本。直到下載與執行完畢後,才會繼續 DOM 的建構。
這將會造成兩難的局面,如果把 <script>
標籤順序擺比較上面,則可能導致如果腳本比較肥大,要載入比較久,進而導致畫面比較晚才被渲染出來。這是為什麼在過去許多人會把 <script>
標籤放在最下面,然而,如果這麼做,則會導致當渲染完畫面後,還要等 script
的載入與執行,這會讓畫面雖然渲染出來,但是沒辦法有功能。
這是為什麼後來 HTML 在 <script>
標籤當中加入了 async
與 defer
。這兩個屬性都是在跟瀏覽器說,不用等腳本的載入,繼續建構 DOM。這讓 DOM 的建構與腳本的載入能夠同步進行,讓使用者體驗可以更好。
async
與 defer
有什麼不同?
雖然兩者有類似的功能,但 async
與 defer
仍有所不同,也適合用在不同的情境。
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 這類分析用的腳本。