<script> 的 async 与 defer 有什么不同?

2023年2月10日

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

「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 上追蹤我們