Giảm phạm vi và độ phức tạp của việc tính toán kiểu

JavaScript thường là trình kích hoạt cho các thay đổi về hình ảnh. Đôi khi, phương pháp này trực tiếp thực hiện những thay đổi đó thông qua các thao tác về kiểu và đôi khi thông qua các phép tính dẫn đến những thay đổi về hình ảnh, chẳng hạn như tìm kiếm hoặc sắp xếp dữ liệu. JavaScript chạy sai thời gian hoặc chạy trong thời gian dài có thể là nguyên nhân phổ biến gây ra vấn đề về hiệu suất và bạn nên tìm cách giảm thiểu tác động của nó nếu có thể.

Tính toán kiểu

Việc thay đổi DOM bằng cách thêm và xoá các phần tử, thay đổi thuộc tính, lớp hoặc phát ảnh động khiến trình duyệt tính toán lại kiểu phần tử và, trong nhiều trường hợp, là bố cục của một phần hoặc toàn bộ trang. Quá trình này gọi là tính toán kiểu tính toán.

Trình duyệt bắt đầu tính các kiểu bằng cách tạo một tập hợp các bộ chọn phù hợp để xác định các lớp, bộ chọn giả và mã nhận dạng sẽ áp dụng cho mọi phần tử nhất định. Sau đó, công cụ này sẽ xử lý các quy tắc kiểu từ bộ chọn phù hợp và tìm ra kiểu cuối cùng mà phần tử có.

Thời gian tính toán lại kiểu và độ trễ tương tác

Lượt tương tác với Nội dung hiển thị tiếp theo (INP) là một chỉ số hiệu suất thời gian chạy tập trung vào người dùng, giúp đánh giá khả năng phản hồi tổng thể của một trang đối với hoạt động đầu vào của người dùng. Mô-đun này đo lường độ trễ tương tác từ khi người dùng tương tác với trang cho đến khi trình duyệt vẽ khung tiếp theo, hiển thị nội dung cập nhật trực quan tương ứng cho giao diện người dùng.

Một thành phần quan trọng của hoạt động tương tác là thời gian cần thiết để vẽ khung hình tiếp theo. Công việc kết xuất hình ảnh được thực hiện để hiển thị khung tiếp theo bao gồm nhiều phần, bao gồm cả việc tính toán kiểu trang xảy ra ngay trước khi bố cục, vẽ và kết hợp. Trang này tập trung vào chi phí tính toán kiểu. Tuy nhiên, việc giảm bất kỳ phần nào của giai đoạn kết xuất liên quan đến hoạt động tương tác cũng sẽ làm giảm tổng độ trễ, bao gồm cả việc tính toán kiểu.

Giảm độ phức tạp của bộ chọn

Việc đơn giản hoá tên bộ chọn có thể giúp bạn tính toán kiểu trên trang nhanh hơn. Các bộ chọn đơn giản nhất tham chiếu một phần tử trong CSS chỉ bằng tên lớp:

.title {
  /* styles */
}

Tuy nhiên, khi bất kỳ dự án nào phát triển, dự án đó có thể cần CSS phức tạp hơn và có thể bạn sẽ thấy các bộ chọn như sau:

.box:nth-last-child(-n+1) .title {
  /* styles */
}

Để xác định cách các kiểu này áp dụng cho trang, trình duyệt phải hỏi "đây có phải là một phần tử có một lớp title có phần tử mẹ là phần tử con trừ-nth-plus-1 có lớp box không?" Việc tìm ra điều này có thể mất nhiều thời gian, tuỳ thuộc vào bộ chọn được sử dụng cũng như trình duyệt đang được đề cập. Để đơn giản hoá việc này, bạn có thể thay đổi bộ chọn thành tên lớp:

.final-box-title {
  /* styles */
}

Những tên lớp thay thế này trông có vẻ khó xử, nhưng lại giúp công việc của trình duyệt đơn giản hơn nhiều. Ví dụ: trong phiên bản trước, để trình duyệt biết một phần tử thuộc loại cuối cùng, trước tiên, trình duyệt phải biết mọi thứ về tất cả các phần tử khác nhằm xác định xem có phần tử nào đứng sau phần tử đó có thể là nth-last-child hay không. Việc này có thể tốn kém hơn nhiều so với việc so khớp một bộ chọn với một phần tử chỉ vì lớp của phần tử đó khớp.

Giảm số lượng phần tử được tạo kiểu

Một yếu tố khác về hiệu suất và thường quan trọng hơn so với độ phức tạp của bộ chọn là khối lượng công việc cần thực hiện khi một phần tử thay đổi.

Nói chung, chi phí trường hợp xấu nhất để tính kiểu phần tử được tính là số lượng phần tử nhân với số lượng bộ chọn, vì trình duyệt cần kiểm tra mỗi phần tử ít nhất một lần so với mọi kiểu để xem chúng có khớp hay không.

Các phép tính kiểu có thể nhắm đến trực tiếp một vài phần tử thay vì làm mất hiệu lực toàn bộ trang. Trong các trình duyệt hiện đại, điều này có xu hướng ít gặp vấn đề vì trình duyệt không phải lúc nào cũng cần kiểm tra tất cả các yếu tố mà thay đổi có thể ảnh hưởng. Mặt khác, các trình duyệt cũ không phải lúc nào cũng được tối ưu hóa cho các tác vụ như vậy. Nếu có thể, bạn nên giảm số lượng phần tử không hợp lệ.

Đo lường chi phí tính toán lại kiểu

Một cách để đo lường chi phí của việc tính toán lại kiểu là sử dụng bảng điều khiển hiệu suất trong Công cụ của Chrome cho nhà phát triển. Hãy làm như sau để bắt đầu:

  1. Mở Công cụ cho nhà phát triển.
  2. Chuyển đến thẻ Hiệu suất.
  3. Nhấp vào Ghi.
  4. Tương tác với trang.

Khi dừng quay, bạn sẽ thấy hình ảnh như sau:

Công cụ cho nhà phát triển hiển thị các phép tính về kiểu.
Báo cáo Công cụ cho nhà phát triển thể hiện cách tính toán kiểu.

Dải ở trên cùng là một biểu đồ ngọn lửa thu nhỏ cũng vẽ biểu đồ các khung hình/giây. Hoạt động càng gần cuối dải thì trình duyệt càng vẽ các khung hình nhanh hơn. Nếu bạn thấy biểu đồ hình ngọn lửa cân bằng ở trên cùng với các thanh màu đỏ phía trên, thì tức là bạn đang xử lý các khung hình chạy trong thời gian dài.

Phóng to vào khu vực gặp sự cố trong Công cụ của Chrome cho nhà phát triển trong bản tóm tắt hoạt động của bảng điều khiển hiệu suất điền sẵn trong Công cụ của Chrome cho nhà phát triển.
Các khung chạy lâu trong bản tóm tắt hoạt động của Công cụ cho nhà phát triển.

Bạn nên xem xét kỹ các khung chạy lâu dài trong một hoạt động tương tác như cuộn. Nếu bạn thấy một khối lớn màu tím, hãy phóng to hoạt động và chọn bất kỳ công việc nào có nhãn Recalculate Style (Tính toán lại kiểu) để biết thêm thông tin về những thao tác tính toán lại kiểu có thể gây tốn kém.

Lấy thông tin chi tiết về các phép tính kiểu lâu dài, bao gồm cả thông tin quan trọng, chẳng hạn như số lượng phần tử chịu ảnh hưởng của việc tính toán lại kiểu.
Quá trình tính toán lại kiểu diễn ra trong thời gian dài chỉ mất hơn 25 mili giây trong bản tóm tắt Công cụ cho nhà phát triển.

Khi nhấp vào sự kiện đó, bạn sẽ thấy ngăn xếp lệnh gọi của sự kiện đó. Nếu việc hiển thị là do tương tác của người dùng, thì công cụ này sẽ gọi JavaScript đã kích hoạt sự thay đổi về kiểu. Báo cáo này cũng cho biết số lượng phần tử mà thay đổi ảnh hưởng đến (chỉ hơn 900 phần tử trong trường hợp này) và thời gian tính toán kiểu. Bạn có thể sử dụng thông tin này để bắt đầu cố gắng tìm bản sửa lỗi trong mã của mình.

Sử dụng Khối, Phần tử, Đối tượng sửa đổi

Các phương pháp lập trình như BEM (Chặn, Phần tử, Công cụ sửa đổi) nạp trong bộ chọn phù hợp với lợi ích về hiệu suất. BEM khuyến nghị rằng mọi thứ đều có một lớp duy nhất và khi bạn cần phân cấp, hệ phân cấp đó cũng được đưa vào tên lớp:

.list {
  /* Styles */
}

.list__list-item {
  /* Styles */
}

Nếu cần một đối tượng sửa đổi, như trong ví dụ về thành phần con cuối cùng, bạn có thể thêm đối tượng sửa đổi đó như sau:

.list__list-item--last-child {
  /* Styles */
}

BEM là một xuất phát điểm phù hợp để sắp xếp CSS của bạn, cả từ góc độ cấu trúc và vì cách đơn giản hoá quá trình tra cứu kiểu.

Nếu không thích BEM, có nhiều cách khác để tiếp cận CSS, nhưng bạn nên đánh giá hiệu suất và tính hiệu quả của BEM trước khi bắt đầu.

Tài nguyên

Hình ảnh chính từ Unsplash, của Markus Spiske.