以為自己瞭解 Async、Defer 和Module?這 5 個誤解會讓你大吃一驚

王大冶發表於2024-10-30
  • React Hook 深入淺出
  • CSS技巧與案例詳解
  • vue2與vue3技巧合集
  • VueUse原始碼解讀

image.png

在2024年的今天,JavaScript的高效載入仍然是最佳化網頁效能的關鍵。然而,許多開發者對指令碼載入屬性(尤其是asyncdefermodule)的細節理解還不夠深入。本文將探討這些屬性的常見誤解,分析它們各自的優缺點,並闡明如何有效使用它們。

誤區一:async 和 defer 是一樣的

實際上,asyncdefer雖然都用於載入外部指令碼而不阻塞HTML解析,但它們的工作方式有所不同:

  • async:指令碼非同步載入,一旦可用就立即執行。這意味著指令碼可能在HTML解析完成之前或之後執行。
  • defer:指令碼與HTML解析並行載入,但只在整個文件解析完成後執行。

優缺點

Async

  • 優點適用於不依賴於完全解析 DOM 的指令碼,如分析。
  • 缺點不能保證執行順序。如果有多個非同步指令碼,它們的執行順序可能會被打亂。

Defer

  • 優點保持執行順序。指令碼在文件解析後執行,確保 DOM 已準備就緒。
  • 缺點只對外部指令碼有效。

示例

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

在這個例子中,analytics.js會在載入完成後立即執行,而main.js會等到文件解析完成後再執行。

誤區二:async 總是比 defer 好

選擇async還是defer取決於指令碼在應用中的角色:

  • 使用async:適用於獨立的指令碼,不依賴DOM或其他指令碼。比如廣告或分析指令碼。
  • 使用defer:適用於需要完整DOM或依賴其他指令碼的情況。比如主應用邏輯。

示例:

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

在這裡,ads.js是非同步載入的,因為它獨立於 DOM,而app.js則推遲執行,直到 DOM 準備就緒。

誤區三:module 屬性僅用於ES6模組

module屬性不僅表示指令碼應被視為ES6模組,還有其他重要特性:

  • 優點:支援現代JavaScript特性,如import/export。自動處於嚴格模式,預設具有defer特性。
  • 缺點:在不使用轉譯器的情況下,舊瀏覽器不支援。

示例:

<script type="module" src="main.js"></script>

在本例中,main.js被視為 ES6 模組,以確保支援現代 JavaScript 功能。

誤區四:內聯指令碼不需要defer

雖然defer只適用於外部指令碼,但瞭解內聯指令碼的執行時機也很重要:

<script>
  // 這段程式碼會立即執行,可能阻塞HTML解析
  console.log("我是內聯指令碼");
</script>

最佳實踐:對於關鍵指令碼,考慮將它們放在body標籤的末尾,以避免阻塞初始渲染。

image.png

誤區五:使用module屬性就能保證最佳效能

雖然module屬性帶來許多好處,但它並不自動保證最佳效能:

  • 轉譯:舊瀏覽器不支援ES6模組,需要轉譯,可能引入效能開銷。
  • HTTP/2:與HTTP/2結合使用可以提高效能,因為多個指令碼可以併發載入而不會阻塞。

示例:

<script type="module">
  import { init } from './app.js';
  init();
</script>

確保構建過程針對基於模組的指令碼進行了最佳化。

結語

透過深入理解asyncdefermodule的差異和適用場景,可以顯著提升web應用的效能和可維護性。希望這篇文章能幫助你在專案中更自信地決定何時以及如何使用這些屬性。

記住,選擇正確的指令碼載入方式可以大大提升使用者體驗。根據應用的具體需求,合理使用這些屬性,讓你的網站載入更快、執行更流暢。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章