Video tải từng phần

Tương tự như với phần tử hình ảnh, bạn cũng có thể tải từng phần của video. Video thường được tải bằng phần tử <video> (mặc dù phương thức thay thế sử dụng <img> đã nổi lên với cách triển khai hạn chế). Tuy nhiên, cách tải từng phần <video> phụ thuộc vào trường hợp sử dụng. Hãy thảo luận một số tình huống mà mỗi tình huống cần một giải pháp riêng.

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

Đối với những video do người dùng thực hiện thao tác phát (tức là video không tự động phát), bạn nên 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ên sử dụng thuộc tính preload có giá trị 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 khi video tải. Lý do là các hành vi mặc định để tải video có thể khác nhau tuỳ theo trình duyệt:

  • Trong Chrome, giá trị mặc định của preload từng là auto, nhưng kể từ Chrome 64, giá trị mặc định hiện tại là metadata. Mặc dù vậy, trên phiên bản Chrome dành cho máy tính, một phần của video có thể được tải trước bằng tiêu đề Content-Range. Các trình duyệt dựa trên Chromium và Firefox khác hoạt động tương tự.
  • Giống như Chrome trên máy tính để bàn, phiên bản Safari 11.0 dành cho máy tính sẽ tải trước một loạt video. Từ phiên bản 11.2, hệ thống chỉ tải trước siêu dữ liệu video. Trong Safari trên iOS, video không bao giờ được tải trước.
  • Khi bật Chế độ tiết kiệm dữ liệu, preload sẽ đặt mặc định thành none.

Vì các hành vi mặc định của trình duyệt liên quan đến preload không được thiết lập một cách cụ thể, nên tốt nhất bạn nên thể hiện rõ ràng. Trong trường hợp người dùng bắt đầu phát, sử dụng preload="none" là cách dễ nhất để trì hoãn việc tải video trên tất cả các nền tảng. Thuộc tính preload không phải là cách duy nhất để trì hoãn việc tải nội dung video. Phát lại nhanh bằng tính năng tải trước video có thể cung cấp cho bạn một số ý tưởng và thông tin chi tiết về cách xử lý tính năng phát video bằng JavaScript.

Tuy nhiên, tính năng này không thực sự hữu ích khi bạn muốn sử dụng video thay cho ảnh GIF động. Chúng ta sẽ đề cập đến phần tiếp theo.

Đối với video có chức năng thay thế ảnh GIF động

Mặc dù ảnh động GIF được sử dụng rộng rãi, nhưng lại kém hiệu quả hơn so với 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ể kéo dài đến vài megabyte dữ liệu. Những video có chất lượng hình ảnh tương tự có xu hướng nhỏ hơn nhiều.

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

  1. Các video này sẽ tự động phát khi được tải.
  2. Chúng 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. Các kênh đó không có bản âm thanh.

Phần tử <video> đạt được điều này sẽ có dạng 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 là những thuộc tính 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ó lựa chọn thay thế video dưới dạng ảnh GIF có thể sử dụng 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ẽ nhận thấy việc bổ sung thuộc tính poster, 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 từng phần. Tương tự như các ví dụ về tải từng phần <img>, hãy lưu trữ URL của video trong thuộc tính data-src của từng phần tử <source>. Từ đó, hãy sử dụng mã JavaScript tương tự như các ví dụ về tải từng phần 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 từng phần một <video>, bạn cần lặp lại tất cả các phần tử con <source> và chuyển thuộc tính data-src của các phần tử đó thành thuộc tính src. Sau khi hoàn tất việc này, 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 trên mỗi 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 GIF động, nhưng không làm tốn nhiều dữ liệu như ảnh GIF động, đồng thời bạn có thể tải từng phần 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 từng phần video:

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

Mỗi thư viện tải từng phần này đều được ghi lại đầy đủ, với nhiều mẫu đánh dấu cho những nỗ lực tải từng phần của bạn.