怎樣做到js無阻塞載入?

王铁柱6發表於2024-12-09

在前端開發中,JavaScript 的阻塞載入會嚴重影響網頁的效能和使用者體驗。當瀏覽器解析 HTML 遇到 <script> 標籤時,會停止解析 HTML,優先下載並執行 JavaScript 程式碼,然後再繼續解析 HTML。如果 JavaScript 程式碼執行時間過長,就會導致頁面渲染延遲,出現“白屏”現象。

為了避免 JavaScript 阻塞載入,可以採用以下幾種方法:

1. 使用 <script async> 屬性:

async 屬性告訴瀏覽器在下載 JavaScript 檔案的同時繼續解析 HTML。JavaScript 檔案下載完成後會立即執行,不會阻塞 HTML 解析。多個帶有 async 屬性的指令碼的執行順序是不確定的,哪個先下載完哪個先執行。

<script async src="script1.js"></script>
<script async src="script2.js"></script>

2. 使用 <script defer> 屬性:

defer 屬性也告訴瀏覽器在下載 JavaScript 檔案的同時繼續解析 HTML。與 async 不同的是,帶有 defer 屬性的指令碼會在 HTML 解析完成後,DOMContentLoaded 事件觸發之前執行。多個帶有 defer 屬性的指令碼會按照它們在 HTML 中出現的順序執行。

<script defer src="script1.js"></script>
<script defer src="script2.js"></script>

3. 將 <script> 標籤放在 <body> 的底部:

<script> 標籤放在 <body> 的底部,可以確保在執行 JavaScript 程式碼之前,HTML 的主體內容已經解析完成並渲染出來。這樣可以避免 JavaScript 阻塞 HTML 解析,提高使用者體驗。

<body>
  <!-- HTML content -->

  <script src="script.js"></script>
</body>

4. 使用動態指令碼插入:

透過 JavaScript 動態建立 <script> 元素並將其新增到文件中,可以實現非同步載入 JavaScript 檔案。

function loadScript(src) {
  const script = document.createElement('script');
  script.src = src;
  script.async = true; // 可選,新增 async 屬性
  document.head.appendChild(script);
}

loadScript('script1.js');
loadScript('script2.js');

5. 使用 import() 動態匯入 (ES Modules):

對於使用 ES Modules 的專案,可以使用 import() 動態匯入模組。這允許按需載入 JavaScript 模組,並且是非同步的。

import('./myModule.js').then(module => {
  // 使用匯入的模組
  module.doSomething();
});

選擇哪種方法?

  • 如果指令碼之間沒有依賴關係,並且不需要訪問 DOM,可以使用 async
  • 如果指令碼之間有依賴關係,或者需要訪問 DOM,並且需要在 DOMContentLoaded 事件觸發之前執行,可以使用 defer
  • <script> 標籤放在 <body> 底部是一種簡單且有效的方法,適用於小型專案或對效能要求不高的場景。
  • 動態指令碼插入和 import() 動態匯入提供了更大的靈活性,適用於需要按需載入 JavaScript 模組的場景。

透過以上方法,可以有效避免 JavaScript 阻塞載入,提高網頁的效能和使用者體驗。 選擇哪種方法取決於你的具體需求和專案規模。 對於現代瀏覽器,asyncdefer 以及 import() 都是很好的選擇。

相關文章