請說說`<script>`、`<script async>`和`<script defer>`的區別

王铁柱6發表於2024-11-21

在前端開發中,<script><script async><script defer> 都用於在 HTML 文件中嵌入 JavaScript 程式碼,但它們在載入和執行指令碼的方式上有所不同,從而影響頁面的渲染效能和行為。

1. <script> (預設行為):

  • 載入和執行: 瀏覽器解析到 <script> 標籤時,會立即停止解析 HTML,下載指令碼檔案,然後執行指令碼。執行完畢後,瀏覽器才會繼續解析剩餘的 HTML。
  • 阻塞: 這是阻塞式的載入方式,意味著在指令碼下載和執行完成之前,頁面渲染會被阻塞。如果指令碼檔案很大或網路速度慢,會導致頁面出現明顯的延遲,使用者體驗不佳。
  • 順序執行: 指令碼會按照它們在 HTML 中出現的順序依次下載和執行。

2. <script async>:

  • 載入和執行: 瀏覽器解析到 <script async> 標籤時,會非同步下載指令碼檔案,不會阻塞 HTML 解析。指令碼下載完成後,瀏覽器會立即暫停 HTML 解析並執行指令碼,執行完畢後再繼續解析 HTML。
  • 非阻塞: 非同步載入,不會阻塞頁面渲染。
  • 執行順序不確定: 多個帶有 async 屬性的指令碼的執行順序是不確定的,它們可能會以任何順序執行,取決於哪個指令碼先下載完成。因此,async 適用於不依賴於其他指令碼或不影響頁面結構的獨立指令碼,例如統計分析指令碼。

3. <script defer>:

  • 載入和執行: 瀏覽器解析到 <script defer> 標籤時,會非同步下載指令碼檔案,不會阻塞 HTML 解析。指令碼下載完成後,會等待 HTML 解析完成,並在 DOMContentLoaded 事件觸發之前執行。
  • 非阻塞: 非同步載入,不會阻塞頁面渲染。
  • 順序執行: 帶有 defer 屬性的指令碼會按照它們在 HTML 中出現的順序執行。這對於需要操作 DOM 或依賴其他指令碼的指令碼非常有用。

總結:

特性 <script> <script async> <script defer>
載入方式 同步 非同步 非同步
阻塞 HTML 解析
執行時機 立即 下載完成後立即執行 HTML 解析完成後,DOMContentLoaded 事件觸發前
執行順序 按順序 不確定 按順序
適用場景 需要立即執行的指令碼,但會阻塞頁面渲染 獨立指令碼,例如統計分析指令碼 需要操作 DOM 或依賴其他指令碼的指令碼,例如初始化程式碼

示例:

<!DOCTYPE html>
<html>
<head>
  <title>Script Example</title>
</head>
<body>
  <script src="script1.js"></script>  <!-- 預設,阻塞 -->
  <script async src="script2.js"></script> <!-- 非同步,執行順序不確定 -->
  <script defer src="script3.js"></script> <!-- 非同步,按順序執行 -->
</body>
</html>

選擇哪種方式取決於指令碼的功能和它們之間的依賴關係。如果指令碼之間沒有依賴關係且不影響頁面渲染,可以使用 async。如果指令碼需要操作 DOM 或依賴其他指令碼,最好使用 defer。 儘量避免使用預設的 <script> 方式,除非指令碼必須立即執行並且可以接受阻塞頁面渲染。