Giới thiệu
Việc vẽ các phần tử cho một trang web hoặc ứng dụng có thể tốn kém và có thể ảnh hưởng tiêu cực đến hiệu suất thời gian chạy của chúng ta. Trong bài viết này, chúng ta sẽ xem nhanh những yếu tố có thể kích hoạt quá trình vẽ trong trình duyệt và cách ngăn chặn việc vẽ không cần thiết.
Painting: Hướng dẫn nhanh
Một trong những nhiệm vụ chính mà trình duyệt phải thực hiện là chuyển đổi DOM và CSS thành pixel trên màn hình. Trình duyệt thực hiện việc này thông qua một quy trình khá phức tạp. Quá trình này bắt đầu bằng cách đọc mã đánh dấu và từ đó tạo một cây DOM. Trình tạo này cũng thực hiện tương tự với CSS và từ đó tạo CSSOM. Sau đó, DOM và CSSOM được kết hợp và cuối cùng, chúng ta sẽ có được một cấu trúc để có thể bắt đầu vẽ một số pixel.
Bản thân quá trình vẽ cũng rất thú vị. Trong Chrome, cây kết hợp của DOM và CSS được một số phần mềm có tên Skia tạo điểm ảnh. Nếu đã từng chơi phần tử canvas
, Skia's API thì bạn sẽ thấy cực kỳ quen thuộc; có nhiều hàm kiểu moveTo
và lineTo
cũng như một loạt hàm nâng cao hơn. Về cơ bản, tất cả các phần tử cần được vẽ đều được tinh lọc thành một tập hợp các lệnh gọi Skia có thể thực thi và kết quả là một loạt bitmap. Các bitmap này được tải lên GPU và GPU giúp hỗ trợ bằng cách kết hợp chúng với nhau để cung cấp cho chúng ta hình ảnh cuối cùng trên màn hình.
Điều cần ghi nhớ là khối lượng công việc của Skia bị ảnh hưởng trực tiếp bởi những phong cách bạn áp dụng cho các phần tử của mình. Nếu bạn sử dụng các kiểu nặng về thuật toán, thì Skia sẽ phải làm nhiều việc hơn. Colt McAnlis đã viết một bài viết về cách CSS ảnh hưởng đến trọng lượng kết xuất trang, vì vậy, bạn nên đọc bài viết đó để hiểu rõ hơn.
Tuy nhiên, việc vẽ sẽ mất thời gian để thực hiện và nếu không giảm thời gian này, chúng ta sẽ vượt quá ngân sách khung hình khoảng 16 mili giây. Người dùng sẽ nhận thấy rằng chúng ta đã bỏ lỡ các khung hình và xem đó là hiện tượng giật, điều này cuối cùng sẽ làm ảnh hưởng đến trải nghiệm người dùng của ứng dụng. Chúng ta thực sự không muốn điều đó xảy ra, vì vậy, hãy xem những điều gì khiến công việc sơn là cần thiết và chúng ta có thể làm gì về vấn đề này.
Thao tác cuộn
Bất cứ khi nào bạn cuộn lên hoặc xuống trong trình duyệt, trình duyệt đó cần vẽ lại nội dung trước khi nội dung đó xuất hiện trên màn hình. Tất cả đều tốt, đó sẽ chỉ là một khu vực nhỏ, nhưng ngay cả khi đó là trường hợp, các phần tử cần được vẽ có thể áp dụng các kiểu phức tạp. Vì vậy, việc bạn có một khu vực nhỏ để vẽ không có nghĩa là quá trình này sẽ diễn ra nhanh chóng.
Để xem những khu vực nào đang được vẽ lại, bạn có thể sử dụng tính năng "Show Paint Rectangles" (Hiển thị hình chữ nhật vẽ) trong Công cụ dành cho nhà phát triển của Chrome (chỉ cần nhấn vào biểu tượng bánh răng nhỏ ở góc dưới bên phải). Sau đó, khi DevTools đang mở, bạn chỉ cần tương tác với trang của mình và bạn sẽ thấy các hình chữ nhật nhấp nháy cho biết vị trí và thời điểm Chrome vẽ một phần trang.
Hiệu suất cuộn là yếu tố quan trọng đối với sự thành công của trang web; người dùng thực sự nhận thấy khi trang web hoặc ứng dụng của bạn không cuộn tốt và họ không thích điều đó. Do đó, chúng ta cần duy trì hoạt động vẽ nhẹ trong khi cuộn để người dùng không thấy hiện tượng giật.
Trước đây, tôi đã viết một bài viết về hiệu suất cuộn. Hãy xem bài viết đó nếu bạn muốn biết thêm về thông tin cụ thể về hiệu suất cuộn.
Lượt tương tác
Hành động tương tác là một nguyên nhân khác gây ra hoạt động vẽ: di chuột, nhấp, chạm, kéo. Bất cứ khi nào người dùng thực hiện một trong những hoạt động tương tác đó, giả sử là di chuột, thì Chrome sẽ phải vẽ lại phần tử bị ảnh hưởng. Đồng thời, cũng giống như với thao tác cuộn, nếu cần có lớp vẽ lớn và phức tạp, bạn sẽ thấy tốc độ khung hình giảm xuống.
Mọi người đều muốn ảnh động tương tác đẹp mắt, mượt mà, vì vậy, chúng ta cần xem liệu các kiểu thay đổi trong ảnh động có tốn quá nhiều thời gian hay không.
Một tổ hợp không may
Điều gì sẽ xảy ra nếu tôi cuộn và vô tình di chuyển chuột cùng một lúc? Tôi có thể vô tình "tương tác" với một phần tử khi cuộn qua phần tử đó, kích hoạt một lượt vẽ tốn kém. Điều này có thể khiến tôi vượt quá ngân sách khung hình khoảng 16,7 mili giây (thời gian chúng ta cần duy trì dưới mức đó để đạt được 60 khung hình/giây). Tôi đã tạo một bản minh hoạ để cho bạn thấy chính xác ý tôi muốn nói. Hy vọng khi cuộn và di chuyển chuột, bạn sẽ thấy hiệu ứng khi di chuột hoạt động. Tuy nhiên, hãy xem Công cụ dành cho nhà phát triển của Chrome tạo ra hiệu ứng này như thế nào:
Trong hình trên, bạn có thể thấy DevTools đang đăng ký công việc sơn khi tôi di chuột qua một trong các khối. Tôi đã sử dụng một số kiểu cực nặng trong bản minh hoạ để làm rõ vấn đề, vì vậy, tôi đang đẩy lên và đôi khi vượt quá ngân sách khung hình. Điều cuối cùng tôi muốn là không phải thực hiện công việc vẽ này một cách không cần thiết, đặc biệt là trong quá trình cuộn khi có công việc khác cần làm!
Vậy làm cách nào để ngăn chặn điều này? Khi điều này xảy ra, bạn có thể triển khai bản sửa lỗi khá đơn giản. Bí quyết ở đây là đính kèm một trình xử lý scroll
sẽ tắt các hiệu ứng khi di chuột và đặt hẹn giờ để bật lại các hiệu ứng đó. Điều đó có nghĩa là chúng tôi đảm bảo rằng khi bạn cuộn, chúng tôi sẽ không cần thực hiện bất kỳ thao tác vẽ tương tác tốn kém nào. Khi bạn đã dừng đủ lâu, chúng tôi cho rằng bạn có thể bật lại các tính năng này một cách an toàn.
Đây là mã:
// Used to track the enabling of hover effects
var enableTimer = 0;
/*
* Listen for a scroll and use that to remove
* the possibility of hover effects
*/
window.addEventListener('scroll', function() {
clearTimeout(enableTimer);
removeHoverClass();
// enable after 1 second, choose your own value here!
enableTimer = setTimeout(addHoverClass, 1000);
}, false);
/**
* Removes the hover class from the body. Hover styles
* are reliant on this class being present
*/
function removeHoverClass() {
document.body.classList.remove('hover');
}
/**
* Adds the hover class to the body. Hover styles
* are reliant on this class being present
*/
function addHoverClass() {
document.body.classList.add('hover');
}
Như bạn có thể thấy, chúng ta sử dụng một lớp trên phần nội dung để theo dõi xem hiệu ứng di chuột có được "cho phép" hay không và các kiểu cơ bản dựa vào lớp này:
/* Expect the hover class to be on the body
before doing any hover effects */
.hover .block:hover {
…
}
Chỉ vậy thôi!
Kết luận
Hiệu suất kết xuất là yếu tố quan trọng để người dùng tận hưởng ứng dụng của bạn. Do đó, bạn phải luôn cố gắng giữ cho mức tải sơn dưới 16 mili giây. Để làm được điều đó, bạn nên tích hợp bằng cách sử dụng DevTools trong suốt quá trình phát triển để xác định và khắc phục nút thắt cổ chai khi chúng xuất hiện.
Tương tác vô tình, đặc biệt là trên các phần tử tốn nhiều màu sơn, có thể rất tốn kém và sẽ giết chết hiệu suất kết xuất. Như bạn đã thấy, chúng ta có thể sử dụng một đoạn mã nhỏ để khắc phục vấn đề đó.
Hãy xem xét các trang web và ứng dụng của bạn, liệu chúng có cần một lớp sơn bảo vệ hay không?