Các phương pháp hay nhất cho tính năng tải từng phần

Mặc dù hình ảnh và video tải từng phần có hiệu suất khả quan và có thể đo lường được những lợi ích thiết thực mà bạn không nên xem nhẹ. Nếu bạn trả lời sai, có thể là những hậu quả không mong muốn. Do đó, bạn cần phải duy trì những các mối lo ngại.

Chú ý đến nếp gấp

Bạn có thể muốn tải từng phần từng tài nguyên phương tiện trên trang bằng JavaScript, nhưng bạn cần phải chống lại sự cám dỗ này. Bất cứ thứ gì nằm ở trên Fold sẽ không được tải từng phần. Những tài nguyên đó nên được coi là quan trọng nội dung và do đó phải được tải bình thường.

Tính năng tải từng phần trì hoãn việc tải tài nguyên cho đến khi DOM tương tác khi tập lệnh tải xong và bắt đầu thực thi. Đối với hình ảnh dưới màn hình đầu tiên, điều này là tốt, nhưng các tài nguyên quan trọng trong màn hình đầu tiên nên được tải bằng phần tử <img> chuẩn để chúng xuất hiện sớm nhất có thể.

Tất nhiên, ngày nay, vị trí của màn hình đầu tiên không rõ ràng đến vậy khi các trang web được xem trên rất nhiều màn hình với kích thước khác nhau. Thiết bị nằm trong màn hình đầu tiên trên máy tính xách tay có thể nằm bên dưới nó trên thiết bị di động. Không có lời khuyên nào là không có dấu đầu dòng giải quyết điều này một cách tối ưu trong mọi tình huống. Bạn sẽ cần tiến hành một tài sản quan trọng trên trang của bạn và tải các hình ảnh đó theo cách thông thường thời trang.

Ngoài ra, bạn có thể không muốn quá nghiêm ngặt về đường gập ngưỡng để kích hoạt tính năng tải từng phần. Điều này có thể lý tưởng hơn nếu bạn muốn thiết lập vùng đệm một khoảng cách dưới màn hình đầu tiên để hình ảnh bắt đầu tải trước khi người dùng cuộn vào khung nhìn. Ví dụ: Intersection Observer API cho phép bạn chỉ định một thuộc tính rootMargin trong một khi bạn tạo một phiên bản IntersectionObserver mới. Chiến dịch này cung cấp hiệu quả cho các phần tử một vùng đệm, kích hoạt hành vi tải từng phần trước khi phần tử nằm trong khung nhìn:

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

Nếu giá trị của rootMargin trông giống với các giá trị mà bạn chỉ định cho một CSS Đó là thuộc tính margin! Trong trường hợp này, lề dưới của phần tử được quan sát (khung nhìn của trình duyệt theo mặc định, nhưng điều này có thể được thay đổi thành một phần tử cụ thể bằng cách sử dụng thuộc tính root) được mở rộng thêm 256 điểm ảnh. Tức là hàm callback sẽ thực thi khi một phần tử hình ảnh được trong phạm vi 256 pixel của khung nhìn và hình ảnh sẽ bắt đầu tải trước khi người dùng thực sự nhìn thấy.

Để đạt được hiệu quả tương tự trong các trình duyệt không hỗ trợ Intersection Observe, hãy sử dụng mã xử lý sự kiện cuộn và điều chỉnh Kiểm tra getBoundingClientRect để thêm một vùng đệm.

Dịch chuyển bố cục và phần giữ chỗ

Nội dung nghe nhìn tải từng phần có thể gây ra hiện tượng dịch chuyển trong bố cục nếu không sử dụng phần giữ chỗ. Những thay đổi này có thể gây mất phương hướng cho người dùng và kích hoạt bố cục DOM tốn kém các hoạt động tiêu tốn tài nguyên hệ thống và góp phần gây ra hiện tượng giật. Ít nhất, hãy cân nhắc sử dụng phần giữ chỗ màu đồng nhất có cùng kích thước với hình ảnh mục tiêu hoặc các kỹ thuật như LQIP hoặc SQIP gợi ý nội dung của một nội dung nghe nhìn mục trước khi tải.

Đối với các thẻ <img>, ban đầu src phải trỏ đến một phần giữ chỗ cho đến khi đó được cập nhật bằng URL hình ảnh cuối cùng. Sử dụng thuộc tính poster trong Phần tử <video> để trỏ đến một hình ảnh giữ chỗ. Ngoài ra, hãy sử dụng width và Thuộc tính height trên cả thẻ <img><video>. Điều này đảm bảo rằng việc chuyển đổi từ phần giữ chỗ sang hình ảnh cuối cùng sẽ không làm thay đổi kích thước được hiển thị của phần tử khi nội dung nghe nhìn tải.

Độ trễ khi giải mã hình ảnh

Việc tải các hình ảnh lớn trong JavaScript và thả chúng vào DOM có thể kết nối luồng chính, khiến giao diện người dùng không phản hồi trong một khoảng thời gian ngắn trong khi quá trình giải mã diễn ra. Giải mã hình ảnh không đồng bộ bằng decode phương thức trước khi chèn chúng vào DOM có thể làm giảm hiện tượng giật này, nhưng hãy lưu ý: Tính năng này hiện chưa có ở mọi nơi và khiến logic tải từng phần trở nên phức tạp hơn. Nếu muốn sử dụng mã này, bạn cần phải kiểm tra. Các chương trình dưới đây cách bạn có thể sử dụng Image.decode() với phương án dự phòng:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

Truy cập đường liên kết CodePen này để xem tương tự như ví dụ thực tế này. Nếu hầu hết các hình ảnh của bạn khá nhỏ, điều này có thể không ảnh hưởng nhiều cho bạn nhưng chắc chắn có thể giúp giảm hiện tượng giật khi tải từng phần các hình ảnh lớn và chèn chúng vào DOM.

Khi nội dung không tải

Đôi khi, tài nguyên đa phương tiện không tải được vì lý do này hay lý do khác và xảy ra lỗi xảy ra. Khi nào việc này có thể xảy ra? Điều đó phụ thuộc, nhưng đây là một tình huống giả định dành cho bạn: Bạn có chính sách lưu vào bộ nhớ đệm HTML trong một khoảng thời gian ngắn (ví dụ: năm phút) và người dùng truy cập vào trang web hoặc mở một thẻ cũ trong trong một khoảng thời gian dài (ví dụ: một vài giờ) và quay lại để đọc nội dung. Tại một thời điểm nào đó trong quá trình này, sẽ xảy ra việc triển khai lại. Trong quá trình triển khai này, một tên của tài nguyên hình ảnh thay đổi do tạo phiên bản dựa trên hàm băm hoặc đã bị xoá hoàn toàn. Vào thời điểm người dùng tải từng phần hình ảnh, tài nguyên sẽ không khả dụng và do đó không thành công.

Mặc dù trường hợp này tương đối hiếm nhưng bạn nên có một bản sao lưu nếu không thể tải từng phần. Đối với hình ảnh, giải pháp này có thể trông giống như sau:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

Những việc bạn quyết định làm trong trường hợp xảy ra lỗi phụ thuộc vào ứng dụng của bạn. Cho Ví dụ: bạn có thể thay thế khu vực giữ chỗ hình ảnh bằng một nút cho phép người dùng cố tải lại hình ảnh hoặc chỉ hiển thị thông báo lỗi trong phần giữ chỗ hình ảnh.

Cũng có thể phát sinh các tình huống khác. Dù bạn làm gì, tốt nhất là tín hiệu cho người dùng khi xảy ra lỗi và có thể đưa ra biện pháp xử lý để thực hiện nếu có vấn đề xảy ra.

Tính khả dụng của JavaScript

Bạn không nên cho rằng JavaScript luôn có sẵn. Nếu bạn định tải từng phần hình ảnh, hãy cân nhắc cung cấp mã đánh dấu <noscript> để hiển thị hình ảnh bằng không có JavaScript theo chữ hoa/chữ thường. Ví dụ dự phòng đơn giản nhất có thể bao gồm sử dụng các phần tử <noscript> để phân phát hình ảnh nếu JavaScript tắt:

Tôi là hình ảnh!

Nếu JavaScript bị tắt, người dùng sẽ thấy cả hình ảnh phần giữ chỗ và hình ảnh chứa các phần tử <noscript>. Để đi xung quanh, hãy đặt một lớp no-js trên thẻ <html> như sau:

<html class="no-js">

Sau đó, hãy đặt một dòng tập lệnh cùng dòng trong <head> trước bất kỳ biểu định kiểu nào được yêu cầu qua các thẻ <link> sẽ xoá lớp no-js khỏi <html> nếu JavaScript bật:

<script>document.documentElement.classList.remove("no-js");</script>

Cuối cùng, hãy sử dụng một số CSS để ẩn các phần tử có lớp lazy khi JavaScript không có sẵn:

.no-js .lazy {
  display: none;
}

Điều này không ngăn hình ảnh giữ chỗ tải, nhưng kết quả sẽ cao hơn đáng mong muốn. Những người đã tắt JavaScript nhận được lợi ích khác ngoài phần giữ chỗ tốt hơn là phần giữ chỗ và không có nội dung hình ảnh có ý nghĩa tất cả.