Video tải từng phần

Ngày xuất bản: 16 tháng 8 năm 2019

Tương tự như phần tử hình ảnh, bạn cũng có thể tải video theo phương thức tải lười. Video thường được tải bằng phần tử <video>, mặc dù đối với video được lưu trữ trên các dịch vụ khác như YouTube, chúng có thể sử dụng <iframe> (trong trường hợp đó, hãy xem bài viết về iframe tải lười).

Cách tải lười <video> phụ thuộc vào trường hợp sử dụng, vì có một số giải pháp khác nhau.

Đối với video không tự động phát

Tốt nhất là bạn nên tránh tự động phát video vì tính năng này sẽ khiến người dùng mất quyền kiểm soát. Trong những trường hợp này, cách tốt nhất để tránh tải toàn bộ video là chỉ định thuộc tính preload trên phần tử <video>:

<video controls preload="none" poster="one-does-not-simply-placeholder.jpg">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Ví dụ trước sử dụng thuộc tính preload có giá trị là none để ngăn trình duyệt tải trước bất kỳ dữ liệu video nào. Thuộc tính poster cung cấp cho phần tử <video> một phần giữ chỗ sẽ chiếm không gian trong khi video tải.

Trong hầu hết các trình duyệt, preload mặc định là metadata và một phần của video được tải trước bằng tiêu đề Content-Range. Điều này có thể dẫn đến việc tải nhiều dữ liệu hơn mong muốn, đặc biệt là nếu trình duyệt không hỗ trợ tiêu đề Content-Range. Ngay cả khi được hỗ trợ, trình duyệt cũng không thể biết siêu dữ liệu được lưu trữ ở byte nào và siêu dữ liệu có thể không được lưu trữ ở đầu tệp. Do đó, cách tốt nhất để tránh tải video là chỉ định none và sử dụng preload="none".

Bạn có thể cải tiến tính năng này để tải trước siêu dữ liệu khi người dùng di chuột qua video bằng thuộc tính onmouseenter (hoặc bằng trình xử lý sự kiện mouseenter tương đương):

<video controls
  preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Điều này không chỉ làm giảm độ trễ khi người dùng phát video mà còn hiển thị thời lượng của video ngay khi họ phát.

Video có thể đủ điều kiện trở thành video đề xuất trong LCP. Hình ảnh poster sẽ tải nhanh hơn video. Vì vậy, nếu hình ảnh này là một đề xuất LCP, bạn nên sử dụng hình ảnh áp phích, đồng thời tải trước hình ảnh đó bằng giá trị thuộc tính fetchpriority"high":

<link rel="preload" href="one-does-not-simply-placeholder.jpg" as="image" fetchpriority="high">
<video controls preload="none"
  poster="one-does-not-simply-placeholder.jpg"
  onmouseenter="event.target.setAttribute('preload','metadata')">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Đối với video đóng vai trò thay thế ảnh GIF động

Video tự động phát thường được dùng cho ảnh động nhanh kiểu GIF. Mặc dù được sử dụng rộng rãi, nhưng ảnh GIF động vẫn thua kém video tương đương về một số khía cạnh, đặc biệt là về kích thước tệp. Ảnh GIF động có thể có kích thước dữ liệu lên đến vài megabyte. Các video có chất lượng hình ảnh tương tự thường có kích thước nhỏ hơn nhiều.

Việc sử dụng phần tử <video> để thay thế cho ảnh GIF động không đơn giản như phần tử <img>. Ảnh GIF động có 3 đặc điểm:

  1. Các video này sẽ tự động phát khi tải.
  2. Các vòng lặp này lặp lại liên tục (mặc dù không phải lúc nào cũng như vậy).
  3. Video không có bản âm thanh.

Bạn có thể thực hiện việc này bằng phần tử <video> như sau:

<video autoplay muted loop playsinline>
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Các thuộc tính autoplay, mutedloop đã tự giải thích. playsinline là cần thiết để tính năng tự động phát xảy ra trong iOS. Giờ đây, bạn đã có một video thay thế dạng GIF có thể sử dụng được trên nhiều nền tảng. Nhưng làm cách nào để tải từng phần? Để bắt đầu, hãy sửa đổi mã đánh dấu <video> cho phù hợp:

<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source data-src="one-does-not-simply.webm" type="video/webm">
  <source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>

Bạn sẽ thấy thuộc tính poster được thêm vào. Thuộc tính này cho phép bạn chỉ định một phần giữ chỗ để chiếm không gian của phần tử <video> cho đến khi video được tải lười. Cũng như các ví dụ về tính năng tải lười <img>, hãy lưu trữ URL video trong thuộc tính data-src trên mỗi phần tử <source>. Từ đó, hãy sử dụng mã JavaScript tương tự như các ví dụ về tính năng tải lười hình ảnh dựa trên Intersection Observer:

document.addEventListener("DOMContentLoaded", function() {
  var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));

  if ("IntersectionObserver" in window) {
    var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(video) {
        if (video.isIntersecting) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});

Khi tải lười một phần tử <video>, bạn cần lặp lại tất cả các phần tử <source> con và chuyển đổi thuộc tính data-src của các phần tử đó thành thuộc tính src. Sau khi thực hiện việc đó, bạn cần kích hoạt quá trình tải video bằng cách gọi phương thức load của phần tử. Sau đó, nội dung nghe nhìn sẽ bắt đầu phát tự động theo thuộc tính autoplay.

Khi sử dụng phương thức này, bạn sẽ có một giải pháp video mô phỏng hành vi của ảnh GIF động, nhưng không gây ra mức sử dụng dữ liệu chuyên sâu như ảnh GIF động và bạn có thể tải lười nội dung đó.

Thư viện tải từng phần

Các thư viện sau đây có thể giúp bạn tải video theo kiểu tải lười:

  • vanilla-lazyloadlozad.js là các tuỳ chọn siêu nhẹ chỉ sử dụng Intersection Observer. Do đó, các tính năng này có hiệu suất cao, nhưng cần được bổ sung trước khi bạn có thể sử dụng trên các trình duyệt cũ.
  • yall.js là một thư viện sử dụng Intersection Observer và quay lại trình xử lý sự kiện. Trình phát cũng có thể tải hình ảnh poster của video theo kiểu tải lười bằng thuộc tính data-poster.
  • Nếu cần một thư viện tải lười dành riêng cho React, bạn có thể cân nhắc sử dụngreact-lazyload. Mặc dù không sử dụng Intersection Observer, nhưng thư viện này vẫn cung cấp một phương thức tải hình ảnh từng phần quen thuộc cho những người đã quen phát triển ứng dụng bằng React.

Mỗi thư viện tải lười này đều được ghi chép cẩn thận, với nhiều mẫu đánh dấu cho nhiều nỗ lực tải lười của bạn.