Tập lệnh của bên thứ ba ảnh hưởng đến hiệu suất. Vì vậy, bạn cần kiểm tra thường xuyên và sử dụng các kỹ thuật tải hiệu quả cho các tập lệnh đó. Lớp học lập trình này cho bạn biết cách tối ưu hoá việc tải tài nguyên của bên thứ ba. Bài viết này đề cập đến các kỹ thuật sau:
Tạm hoãn việc tải tập lệnh
Tải từng phần các tài nguyên không quan trọng
Kết nối trước với các nguồn gốc bắt buộc
Ứng dụng mẫu đi kèm có một trang web đơn giản với ba tính năng đến từ các nguồn bên thứ ba:
Video được nhúng
Thư viện trực quan hoá dữ liệu để kết xuất biểu đồ dạng đường
Tiện ích chia sẻ trên mạng xã hội
Bạn sẽ bắt đầu bằng cách đo lường hiệu suất của ứng dụng, sau đó áp dụng từng kỹ thuật để cải thiện các khía cạnh khác nhau của hiệu suất ứng dụng.
Đo lường hiệu suất
Trước tiên, hãy mở ứng dụng mẫu ở chế độ xem toàn màn hình:
- Nhấp vào Remix to Edit (Trộn lại để chỉnh sửa) để có thể chỉnh sửa dự án.
- Để xem trước trang web, hãy nhấn vào Xem ứng dụng. Sau đó, nhấn vào biểu tượng Màn hình toàn cảnh .
Chạy quy trình kiểm tra hiệu suất Lighthouse trên trang để thiết lập hiệu suất cơ sở:
- Nhấn tổ hợp phím `Ctrl+Shift+J` (hoặc `Command+Option+J` trên máy Mac) để mở DevTools.
- Nhấp vào thẻ Lighthouse (Tháp hải đăng).
- Nhấp vào Thiết bị di động.
- Chọn hộp đánh dấu Hiệu suất. (Bạn có thể bỏ chọn các hộp đánh dấu còn lại trong phần Kiểm tra.)
- Nhấp vào Mạng 3G nhanh được mô phỏng, hệ số giảm tốc CPU gấp 4 lần.
- Chọn hộp đánh dấu Xoá bộ nhớ.
- Nhấp vào Chạy quy trình kiểm tra.
Khi chạy quy trình kiểm tra trên máy, kết quả chính xác có thể khác nhau, nhưng bạn sẽ nhận thấy thời gian Hiển thị nội dung đầu tiên (FCP) khá cao và Lighthouse đề xuất hai cơ hội để điều tra: Loại bỏ tài nguyên chặn kết xuất và Kết nối trước với các nguồn gốc bắt buộc. (Ngay cả khi tất cả các chỉ số đều có màu xanh lục, các biện pháp tối ưu hoá vẫn sẽ mang lại hiệu quả cải thiện.)
Tạm hoãn JavaScript của bên thứ ba
Quy trình kiểm tra Loại bỏ các tài nguyên chặn hiển thị cho thấy bạn có thể tiết kiệm thời gian bằng cách trì hoãn một tập lệnh đến từ d3js.org:
D3.js là một thư viện JavaScript để tạo hình ảnh trực quan về dữ liệu. Tệp script.js
trong ứng dụng mẫu sử dụng các hàm tiện ích D3 để tạo biểu đồ đường SVG và thêm biểu đồ đó vào trang. Thứ tự thao tác ở đây rất quan trọng: script.js
phải chạy sau khi tài liệu được phân tích cú pháp và thư viện D3 đã tải, đó là lý do tại sao script.js
được đưa vào ngay trước thẻ </body>
đóng trong index.html
.
Tuy nhiên, tập lệnh D3 được đưa vào <head>
của trang, ngăn việc phân tích cú pháp tài liệu còn lại:
Hai thuộc tính ma thuật có thể bỏ chặn trình phân tích cú pháp khi được thêm vào thẻ tập lệnh:
async
đảm bảo rằng các tập lệnh tải xuống ở chế độ nền và thực thi ngay khi có cơ hội đầu tiên sau khi tải xuống xong.defer
đảm bảo rằng các tập lệnh tải xuống ở chế độ nền và thực thi sau khi phân tích cú pháp hoàn tất.
Vì biểu đồ này không thực sự quan trọng đối với toàn bộ trang và rất có thể sẽ nằm ở phần dưới cùng của trang, hãy sử dụng defer
để đảm bảo không có trình phân tích cú pháp nào bị chặn.
Bước 1: Tải tập lệnh không đồng bộ bằng thuộc tính defer
Trên dòng 17 trong index.html
, hãy thêm thuộc tính defer
vào phần tử <script>
:
<script src="https://d3js.org/d3.v3.min.js" defer></script>
Bước 2: Đảm bảo thứ tự các phép toán là chính xác
Giờ đây, D3 bị trì hoãn, script.js
sẽ chạy trước khi D3 sẵn sàng, dẫn đến lỗi.
Các tập lệnh có thuộc tính defer
sẽ thực thi theo thứ tự được chỉ định. Để đảm bảo script.js
được thực thi sau khi D3 đã sẵn sàng, hãy thêm defer
vào và di chuyển defer
lên <head>
của tài liệu, ngay sau phần tử <script>
D3. Giờ đây, trình phân tích cú pháp không còn bị chặn và quá trình tải xuống bắt đầu sớm hơn.
<script src="https://d3js.org/d3.v3.min.js" defer></script>
<script src="./script.js" defer></script>
Tải từng phần tài nguyên của bên thứ ba
Tất cả tài nguyên nằm dưới màn hình đầu tiên đều là ứng viên phù hợp để tải từng phần.
Ứng dụng mẫu có một video trên YouTube được nhúng trong iframe. Cách kiểm tra số lượng yêu cầu mà trang thực hiện và số lượng yêu cầu đến từ iframe YouTube được nhúng:
- Để xem trước trang web, hãy nhấn vào Xem ứng dụng. Sau đó, nhấn vào biểu tượng Màn hình toàn cảnh .
- Nhấn tổ hợp phím `Ctrl+Shift+J` (hoặc `Command+Option+J` trên máy Mac) để mở DevTools.
- Nhấp vào thẻ Mạng.
- Chọn hộp đánh dấu Tắt bộ nhớ đệm.
- Chọn 3G nhanh trong trình đơn thả xuống Giới hạn băng thông.
- Tải lại trang.
Bảng điều khiển Mạng cho thấy trang đã thực hiện tổng cộng 28 yêu cầu và chuyển gần 1 MB tài nguyên nén.
Để xác định các yêu cầu mà iframe
của YouTube đã đưa ra, hãy tìm mã video 6lfaiXM6waw
trong cột Đầu mối kích hoạt. Cách nhóm tất cả các yêu cầu theo miền:
Trong bảng điều khiển Mạng, hãy nhấp chuột phải vào tiêu đề cột.
Trong trình đơn thả xuống, hãy chọn cột Miền.
Để sắp xếp các yêu cầu theo miền, hãy nhấp vào tiêu đề cột Miền.
Cách sắp xếp mới cho thấy có thêm các yêu cầu đối với các miền của Google. Tổng cộng, iframe YouTube tạo ra 14 yêu cầu về tập lệnh, tệp kiểu, hình ảnh và phông chữ. Tuy nhiên, trừ phi người dùng thực sự cuộn xuống để phát video, họ không thực sự cần tất cả các thành phần đó.
Bằng cách chờ tải từng phần video cho đến khi người dùng cuộn xuống phần đó của trang, bạn sẽ giảm số lượng yêu cầu mà trang thực hiện ban đầu. Phương pháp này giúp tiết kiệm dữ liệu của người dùng và tăng tốc độ tải ban đầu.
Một cách để triển khai tính năng tải lười là sử dụng Intersection Observer, một API trình duyệt sẽ thông báo cho bạn khi một phần tử vào hoặc thoát khỏi khung nhìn của trình duyệt.
Bước 1: Ngăn video tải ban đầu
Để tải lười khung video, trước tiên, bạn phải ngăn khung video tải theo cách thông thường. Bạn có thể thực hiện việc này bằng cách thay thế thuộc tính src
bằng thuộc tính data-src
để chỉ định URL của video:
<iframe width="560" height="315" data-src="https://www.youtube.com/embed/lS9D6w1GzGY" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
data-src
là một thuộc tính dữ liệu, cho phép bạn lưu trữ thêm thông tin về các phần tử HTML tiêu chuẩn. Bạn có thể đặt tên bất kỳ cho thuộc tính dữ liệu, miễn là tên đó bắt đầu bằng "data-".
Một iframe không có src
sẽ không tải được.
Bước 2: Sử dụng Intersection Observer để tải lười video
Để tải video khi người dùng cuộn đến video đó, bạn cần biết thời điểm điều đó xảy ra. Đó là lúc Intersection Observer API xuất hiện. Intersection Observer API cho phép bạn đăng ký một hàm gọi lại được thực thi bất cứ khi nào một phần tử mà bạn muốn theo dõi vào hoặc ra khỏi khung nhìn.
Để bắt đầu, hãy tạo một tệp mới và đặt tên là lazy-load.js
:
- Nhấp vào Tệp mới rồi đặt tên cho tệp.
- Nhấp vào Thêm tệp này.
Thêm thẻ tập lệnh vào đầu tài liệu:
<script src="/lazy-load.js" defer></script>
Trong lazy-load.js
, hãy tạo một IntersectionObserver
mới và truyền vào đó một hàm gọi lại để chạy:
// create a new Intersection Observer
let observer = new IntersectionObserver(callback);
Bây giờ, hãy cung cấp cho observer
một phần tử mục tiêu để xem (iframe video trong trường hợp này) bằng cách truyền phần tử đó dưới dạng đối số trong phương thức observe
:
// the element that you want to watch
const element = document.querySelector('iframe');
// register the element with the observe method
observer.observe(element);
callback
nhận danh sách các đối tượng IntersectionObserverEntry
và chính đối tượng IntersectionObserver
. Mỗi mục nhập chứa một phần tử target
và các thuộc tính mô tả kích thước, vị trí, thời gian mục nhập đó xuất hiện trong khung nhìn, v.v. Một trong các thuộc tính của IntersectionObserverEntry
là isIntersecting
– một giá trị boolean bằng true
khi phần tử này vào khung nhìn.
Trong ví dụ này, target
là iframe
. isIntersecting
bằng true
khi target
vào khung nhìn. Để xem mã này hoạt động như thế nào trên thực tế, hãy thay thế callback
bằng hàm sau:
let observer = new IntersectionObserver(callback);
let observer = new IntersectionObserver(function(entries, observer) {
entries.forEach(entry => {
console.log(entry.target);
console.log(entry.isIntersecting);
});
});
- Để xem trước trang web, hãy nhấn vào Xem ứng dụng. Sau đó, nhấn vào biểu tượng Màn hình toàn cảnh .
- Nhấn tổ hợp phím `Ctrl+Shift+J` (hoặc `Command+Option+J` trên máy Mac) để mở DevTools.
- Nhấp vào thẻ Bảng điều khiển.
Hãy thử cuộn lên và xuống. Bạn sẽ thấy giá trị của isIntersecting
thay đổi và phần tử mục tiêu được ghi vào bảng điều khiển.
Để tải video khi người dùng cuộn đến vị trí của video, hãy sử dụng isIntersecting
làm điều kiện để chạy hàm loadElement
. Hàm này sẽ lấy giá trị từ data-src
của phần tử iframe
và đặt giá trị đó làm thuộc tính src
của phần tử iframe
. Thao tác thay thế đó sẽ kích hoạt quá trình tải video. Sau đó, khi video tải xong, hãy gọi phương thức unobserve
trên observer
để ngừng xem phần tử mục tiêu:
let observer = new IntersectionObserver(function (entries, observer) {
entries.forEach(entry => {
console.log(entry.target);
console.log(entry.isIntersecting);
});
});
if (entry.isIntersecting) {
// do this when the element enters the viewport
loadElement(entry.target);
// stop watching
observer.unobserve(entry.target);
}
});
});
function loadElement(element) {
const src = element.getAttribute('data-src');
element.src = src;
}
Bước 3: Đánh giá lại hiệu suất
Để xem kích thước và số lượng tài nguyên đã thay đổi như thế nào, hãy mở bảng điều khiển Network (Mạng) của DevTools rồi tải lại trang. Bảng điều khiển Mạng cho thấy rằng trang đã thực hiện 14 yêu cầu và chỉ có 260 KB. Đó là một điểm cải tiến có ý nghĩa!
Bây giờ, hãy di chuyển xuống cuối trang và chú ý đến bảng điều khiển Network (Mạng). Khi truy cập vào video, bạn sẽ thấy trang kích hoạt các yêu cầu bổ sung.
Kết nối trước với những nguồn gốc bắt buộc
Bạn đã trì hoãn JavaScript không quan trọng và tải lười các yêu cầu của YouTube. Giờ đây, đã đến lúc tối ưu hoá nội dung còn lại của bên thứ ba.
Việc thêm thuộc tính rel=preconnect
vào một đường liên kết sẽ yêu cầu trình duyệt thiết lập kết nối với một miền trước khi yêu cầu tài nguyên đó được thực hiện. Tốt nhất bạn nên sử dụng thuộc tính này trên các nguồn gốc cung cấp tài nguyên mà bạn chắc chắn trang cần.
Kết quả kiểm tra Lighthouse mà bạn đã chạy ở bước đầu tiên trong phần Kết nối trước với các nguồn gốc bắt buộc cho thấy bạn có thể tiết kiệm khoảng 400 mili giây bằng cách thiết lập các kết nối sớm với staticxx.facebook.com và youtube.com:
Vì video trên YouTube hiện được tải từng phần nên chỉ còn staticxx.facebook.com, nguồn của tiện ích chia sẻ trên mạng xã hội. Việc thiết lập kết nối sớm với miền này cũng đơn giản như việc thêm thẻ <link>
vào <head>
của tài liệu:
<link rel="preconnect" href="https://staticxx.facebook.com">
Đánh giá lại hiệu suất
Dưới đây là trạng thái của trang sau khi tối ưu hoá. Làm theo các bước trong phần Đo lường hiệu suất của lớp học lập trình để chạy một quy trình kiểm tra Lighthouse khác.