Tải trước mô-đun

Sérgio Gomes

Việc phát triển dựa trên mô-đun mang lại một số lợi thế thực sự về khả năng lưu bộ nhớ đệm, giúp bạn giảm số lượng byte cần thiết để gửi đến người dùng. Mã chi tiết hơn cũng giúp ích cho quá trình tải bài hát, bằng cách cho phép bạn ưu tiên mã quan trọng trong ứng dụng của bạn.

Tuy nhiên, các phần phụ thuộc của mô-đun gây ra sự cố tải, trong đó trình duyệt cần chờ một mô-đun tải trước khi nó phát hiện các phần phụ thuộc của mô-đun đó là gì. Một chiều bằng cách tải trước các phần phụ thuộc để trình duyệt biết về tất cả các phần các tệp trước và có thể khiến kết nối bận.

<link rel="preload"> là một cách tuyên bố yêu cầu tài nguyên trước, trước khi trình duyệt cần đến.

<head>
  <link rel="preload" as="style" href="critical-styles.css">
  <link rel="preload" as="font" crossorigin type="font/woff2" href="myfont.woff2">
</head>

Hỗ trợ trình duyệt

  • Chrome: 50.
  • Cạnh: ≤79.
  • Firefox: 85.
  • Safari: 11.1.

Nguồn

Điều này đặc biệt hiệu quả với các tài nguyên như phông chữ, thường bị ẩn bên trong các tệp CSS, đôi khi sâu đến một vài cấp. Trong trường hợp đó, trình duyệt sẽ phải đợi nhiều lượt khứ hồi trước khi nhận thấy cần phải tìm nạp một tệp phông chữ lớn, trong khi lẽ ra tệp này có thể dùng khoảng thời gian đó để bắt đầu tải xuống và tận dụng toàn bộ băng thông kết nối.

<link rel="preload"> và tiêu đề HTTP tương đương của nó cung cấp thông tin khai báo đơn giản giúp trình duyệt biết ngay về các tệp quan trọng cần thiết như một phần của thao tác điều hướng hiện tại. Khi trình duyệt thấy tải trước, nó sẽ bắt đầu ưu tiên tải xuống cho tài nguyên để vào thời điểm thực sự cần đến tài nguyên đó: đã được tìm nạp hoặc một phần ở đó. Tuy nhiên, bạn không thể sử dụng tính năng này cho các mô-đun.

Đây là lúc mọi thứ trở nên phức tạp. Có nhiều chế độ thông tin xác thực cho và để nhận được kết quả tìm kiếm trong bộ nhớ đệm, chúng phải khớp, nếu không, bạn sẽ tìm nạp tài nguyên hai lần. Không cần phải nói rằng tìm nạp hai lần là không tốt vì cách này làm lãng phí băng thông của người dùng và khiến họ phải chờ lâu hơn mà không có lý do chính đáng.

Đối với thẻ <script><link>, bạn có thể đặt chế độ thông tin xác thực bằng crossorigin . Tuy nhiên, hoá ra <script type="module"> không có Thuộc tính crossorigin cho biết chế độ thông tin xác thực omit không tồn tại trong <link rel="preload">. Điều này có nghĩa là bạn sẽ phải thay đổi thuộc tính crossorigin trong cả <script><link> thành một các giá trị khác và có thể bạn sẽ không dễ dàng thực hiện việc này nếu cố gắng tải trước là phần phụ thuộc của các mô-đun khác.

Hơn nữa, việc tìm nạp tệp chỉ là bước đầu tiên để thực sự chạy mã. Trước tiên, trình duyệt phải phân tích cú pháp và biên dịch tệp. Tốt nhất là bạn nên điều này cũng sẽ xảy ra trước để khi cần mô-đun, mã sẵn sàng chạy. Tuy nhiên, V8 (công cụ JavaScript của Chrome) phân tích cú pháp và biên dịch các mô-đun khác với JavaScript khác. <link rel="preload"> không cung cấp bất kỳ cách nào để cho biết tệp đang được tải là một mô-đun, vì vậy tất cả trình duyệt có thể làm là tải tệp vào bộ nhớ đệm. Sau khi tập lệnh được tải bằng cách sử dụng <script type="module"> (hoặc thẻ được tải bởi một mô-đun khác), trình duyệt phân tích cú pháp và biên dịch mã dưới dạng mô-đun JavaScript.

Tóm lại là có. Bằng cách sử dụng một loại link cụ thể cho các mô-đun tải trước, chúng ta có thể viết HTML đơn giản mà không phải lo lắng về chế độ thông tin xác thực mà chúng tôi đang sử dụng. Chiến lược phát hành đĩa đơn mặc định chỉ hoạt động.

<head>
  <link rel="modulepreload" href="super-critical-stuff.mjs">
</head>
[...]
<script type="module" src="super-critical-stuff.mjs">

Và vì trình duyệt giờ đây biết rằng nội dung bạn đang tải trước là một mô-đun, nên có thể rồi phân tích cú pháp và biên dịch mô-đun ngay khi tìm nạp xong, thay vì đợi cho đến khi nó cố chạy.

Hỗ trợ trình duyệt

  • Chrome: 66.
  • Cạnh: ≤79.
  • Firefox: 115.
  • Safari: 17.

Nguồn

Thế còn mô-đun thì sao phần phụ thuộc?

Thật hài hước khi hỏi phải vậy! Thực sự có một thứ mà bài viết này chưa đề cập đến, đó là đệ quy.

Thông số kỹ thuật <link rel="modulepreload"> thực sự cho phép tải tuỳ chọn, không chỉ mô-đun được yêu cầu mà còn có tất cả cây phụ thuộc của mô-đun đó. Trình duyệt không phải làm điều này, nhưng chúng có thể.

Vậy giải pháp nào là tốt nhất trên nhiều trình duyệt để tải trước một mô-đun và cây phụ thuộc, vì bạn sẽ cần cây phụ thuộc đầy đủ để chạy ứng dụng?

Các trình duyệt chọn tải trước các phần phụ thuộc theo cách đệ quy nên có tính năng loại bỏ trùng lặp mạnh mẽ mô-đun, vì vậy nhìn chung phương pháp hay nhất là khai báo mô-đun và danh sách phẳng phần phụ thuộc của trình duyệt đó và tin tưởng trình duyệt sẽ không tìm nạp cùng một mô-đun hai lần.

<head>
  <!-- dog.js imports dog-head.js, which in turn imports
       dog-head-mouth.js, which imports dog-head-mouth-tongue.js. -->
  <link rel="modulepreload" href="dog-head-mouth-tongue.mjs">
  <link rel="modulepreload" href="dog-head-mouth.mjs">
  <link rel="modulepreload" href="dog-head.mjs">
  <link rel="modulepreload" href="dog.mjs">
</head>

Việc tải trước mô-đun có giúp cải thiện hiệu suất không?

Tính năng tải trước có thể giúp tối đa hoá mức sử dụng băng thông, bằng cách cho trình duyệt biết về những gì nó cần tìm nạp để nó không bị kẹt mà không làm gì trong suốt những chuyến khứ hồi dài đó. Nếu bạn đang thử nghiệm các mô-đun và gặp phải vấn đề về hiệu suất do cây phụ thuộc, việc tạo một danh sách phẳng các nội dung tải trước chắc chắn có thể giúp ích.

Tuy nhiên, hiệu suất của mô-đun vẫn đang được cải thiện, vì vậy, hãy đảm bảo bạn xem xét kỹ những gì đang xảy ra trong ứng dụng của mình bằng Công cụ dành cho nhà phát triển, và trong thời gian chờ đợi, hãy cân nhắc việc gói ứng dụng của bạn thành nhiều phần. Có rất nhiều mô-đun đang diễn ra trong Chrome, vì vậy chúng tôi đang tiến gần hơn đến việc cung cấp việc nghỉ ngơi đầy đủ của họ!