Giảm tải JavaScript bằng cách phân tách mã

Hầu hết các trang web và ứng dụng đều được tạo thành từ nhiều phần khác nhau. Thay vì gửi tất cả JavaScript tạo nên ứng dụng ngay khi trang được tải thì chia JavaScript thành nhiều phần cải thiện hiệu suất của trang.

Lớp học lập trình này cho biết cách sử dụng tính năng phân tách mã để cải thiện hiệu suất của một ứng dụng đơn giản sắp xếp ba số.

Một cửa sổ trình duyệt cho thấy một ứng dụng có tên là Magic Sorter, trong đó có 3 trường để nhập số và nút sắp xếp.

Đo

Như thường lệ, trước tiên, bạn cần đo lường hiệu suất của một trang web trước khi cố gắng thêm bất kỳ cách tối ưu hoá nào.

  1. Để xem trước trang web, hãy nhấn vào Xem ứng dụng. Sau đó nhấn Toàn màn hình toàn màn hình.
  2. Nhấn tổ hợp phím "Control + Shift + J" (hoặc "Command+Option+J" trên máy Mac) để mở Công cụ cho nhà phát triển.
  3. Nhấp vào thẻ Mạng.
  4. Chọn hộp kiểm Tắt bộ nhớ đệm.
  5. Tải lại ứng dụng.

Bảng điều khiển mạng hiển thị gói JavaScript 71,2 KB.

JavaScript có giá trị 71,2 KB chỉ để sắp xếp một vài số trong ứng dụng đơn giản. What gives?

Trong mã nguồn (src/index.js), thư viện lodash được nhập và sử dụng trong ứng dụng này. Lodash cung cấp nhiều tiện ích hữu ích nhưng chỉ sử dụng một phương thức duy nhất trong gói ở đây. Cài đặt và nhập toàn bộ các phần phụ thuộc của bên thứ ba chỉ trong đó một phần nhỏ đang được sử dụng một phần là một sai lầm phổ biến.

Tối ưu hoá

Có một số cách để cắt kích thước gói:

  1. Viết một phương pháp sắp xếp tuỳ chỉnh thay vì nhập thư viện của bên thứ ba
  2. Sử dụng phương thức Array.prototype.sort() tích hợp sẵn để sắp xếp theo số
  3. Chỉ nhập phương thức sortBy từ lodash chứ không phải toàn bộ thư viện
  4. Tải mã xuống để chỉ sắp xếp khi người dùng nhấp vào nút

Phương án 1 và 2 là các phương pháp hoàn toàn thích hợp để giảm kích thước gói (và có thể sẽ phù hợp nhất với ứng dụng thực tế). Tuy nhiên, đó chính là không được sử dụng trong hướng dẫn này nhằm mục đích giảng dạy 😈.

Cả hai lựa chọn 3 và 4 đều giúp cải thiện hiệu suất của ứng dụng này. Chiến lược phát hành đĩa đơn một số phần tiếp theo của lớp học lập trình này sẽ đề cập đến các bước này. Giống như mọi đoạn mã lập trình khác hướng dẫn, luôn cố gắng tự viết mã thay vì sao chép và dán.

Chỉ nhập những thông tin bạn cần

Bạn cần sửa đổi một vài tệp để chỉ nhập phương thức duy nhất từ lodash. Để bắt đầu, hãy thay thế phần phụ thuộc này trong package.json:

"lodash": "^4.7.0",

bằng cách:

"lodash.sortby": "^4.7.0",

Bây giờ, trong src/index.js, hãy nhập mô-đun cụ thể này:

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

Và cập nhật cách các giá trị được sắp xếp:

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

Tải lại ứng dụng, mở Công cụ cho nhà phát triển và xem bảng điều khiển Mạng một lần nữa.

Bảng điều khiển mạng hiển thị gói JavaScript 15,2 KB.

Đối với ứng dụng này, kích thước gói đã giảm hơn 4 lần với rất ít hiệu quả hơn, nhưng vẫn còn nhiều khía cạnh cần cải thiện.

Phân chia mã

webpack là một trong những nguồn mở phổ biến nhất các gói mô-đun được sử dụng hiện nay. Tóm lại, API này nhóm tất cả các mô-đun JavaScript (dưới dạng cũng như các nội dung khác) tạo nên một ứng dụng web thành các tệp tĩnh có thể trình duyệt đọc được.

Gói duy nhất được sử dụng trong ứng dụng này có thể được chia thành hai gói riêng biệt phân đoạn:

  • Người chịu trách nhiệm về mã tạo nên tuyến ban đầu của chúng ta
  • Phân đoạn phụ chứa mã sắp xếp

Với việc sử dụng tính năng nhập động, một phân đoạn phụ có thể được tải từng phần, hoặc được tải theo yêu cầu. Trong ứng dụng này, mã tạo nên phân đoạn có thể là chỉ được tải khi người dùng nhấn nút.

Bắt đầu bằng cách xoá lệnh nhập cấp cao nhất cho phương thức sắp xếp trong src/index.js:

import sortBy from "lodash.sortby";

Sau đó, hãy nhập sự kiện đó vào trình nghe sự kiện để kích hoạt khi nhấn nút:

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

Tính năng import() là một phần của đề xuất (hiện đang ở giai đoạn 3 của quy trình TC39) để bao gồm khả năng nhập động một mô-đun. webpack đã bao gồm tính năng hỗ trợ cho thao tác này và tuân theo cú pháp tương tự được đặt theo đề xuất.

import() trả về một lời hứa và khi giải quyết, biến được chọn mô-đun được cung cấp được chia thành một phần riêng biệt. Sau khi mô-đun là trả về, module.default dùng để tham chiếu giá trị mặc định dữ liệu xuất do lodash cung cấp. Lời hứa được xâu chuỗi bằng một .then khác gọi một phương thức sortInput để sắp xếp 3 giá trị đầu vào. Ở cuối chuỗi hứa hẹn, .catch() dùng để xử lý các trường hợp lời hứa bị từ chối do lỗi.

Việc cuối cùng cần làm là ghi phương thức sortInput ở cuối tệp. Đây phải là một hàm trả về một hàm lấy phương thức đã nhập từ lodash.sortBy. Sau đó, hàm được lồng có thể sắp xếp ba giá trị đầu vào và cập nhật DOM.

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

Giám Sát

Tải lại ứng dụng lần cuối và theo dõi kỹ Mạng bảng điều khiển. Chỉ một gói nhỏ ban đầu được tải xuống ngay khi ứng dụng tải.

Bảng điều khiển mạng hiển thị gói JavaScript 2,7 KB.

Sau khi nhấn nút để sắp xếp các số đầu vào, đoạn chứa mã sắp xếp được tìm nạp và thực thi.

Bảng điều khiển mạng hiển thị gói JavaScript 2,7 KB, theo sau là gói JavaScript 13,9 KB.

Hãy lưu ý cách các số vẫn được sắp xếp!

Kết luận

Tách mã và tải từng phần có thể là những kỹ thuật cực kỳ hữu ích để cắt giảm kích thước gói ban đầu của ứng dụng và điều này có thể trực tiếp dẫn đến thời gian tải trang nhanh hơn nhiều. Tuy nhiên, có một số điều quan trọng mà bạn cần được xem xét trước khi đưa tối ưu hoá này vào ứng dụng của bạn.

Giao diện người dùng tải từng phần

Khi tải từng phần của các mô-đun mã cụ thể, bạn cần xem xét cách trải nghiệm người dùng có kết nối mạng yếu hơn. Tách và khi tải một đoạn mã rất lớn khi người dùng gửi một hành động, có vẻ như ứng dụng đã ngừng hoạt động, vì vậy hãy cân nhắc hiển thị đang tải chỉ báo của một số loại.

Tải từng phần các mô-đun nút của bên thứ ba

Không phải lúc nào đây cũng là phương pháp tốt nhất để tải từng phần các phần phụ thuộc của bên thứ ba trong ứng dụng của bạn và điều đó phụ thuộc vào nơi bạn sử dụng chúng. Thông thường, bên thứ ba các phần phụ thuộc được tách thành một gói vendor riêng biệt có thể được lưu vào bộ nhớ đệm nhưng chúng không cập nhật thường xuyên. Đọc thêm về cách SplitChunksPlugin có thể giúp bạn làm việc này.

Tải từng phần bằng khung JavaScript

Nhiều khung và thư viện phổ biến sử dụng gói web cung cấp các thành phần trừu tượng thực hiện tải từng phần dễ dàng hơn so với sử dụng tính năng nhập động ở giữa .

Mặc dù rất hữu ích khi hiểu cách hoạt động của tính năng nhập động, nhưng hãy luôn sử dụng mà khung/thư viện của bạn đề xuất để tải từng phần các mô-đun cụ thể.

Tải trước và tìm nạp trước

Nếu có thể, hãy tận dụng gợi ý của trình duyệt như <link rel="preload"> hoặc <link rel="prefetch"> để thử và tải các mô-đun quan trọng thậm chí sớm hơn. webpack hỗ trợ cả hai gợi ý thông qua việc sử dụng nhận xét thần kỳ trong quá trình nhập tuyên bố. Điều này được giải thích chi tiết hơn trong Hướng dẫn Tải trước các đoạn quan trọng.

Tải từng phần không chỉ áp dụng cho mã

Hình ảnh có thể tạo nên một phần quan trọng của ứng dụng. Tải từng phần những trang web nằm dưới màn hình đầu tiên hoặc bên ngoài khung nhìn của thiết bị, có thể tăng tốc độ trang web. Đã đọc tìm hiểu thêm về vấn đề này trong Hướng dẫn về Lazysize.