Video tải từng phần

Tương tự như với thành phần hình ảnh, bạn cũng có thể tải từng phần video. Video thường được tải bằng phần tử <video> (mặc dù một phương thức thay thế sử dụng <img> đã xuất hiệ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 cùng thảo luận một số tình huống mà mỗi trường hợp đòi hỏi một giải pháp riêng.

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

Đối với những video mà người dùng yêu cầu phát (tức là những video không tự động phát), bạn nên chỉ định thuộc tính preload cho 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 trong khi video tải. Nguyên nhân là do các hành vi mặc định để tải video có thể khác nhau giữa các trình duyệt:

  • Trong Chrome, giá trị mặc định cho preload trước đây 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 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ự nhau.
  • Giống như Chrome trên máy tính, 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 của video. Trong Safari trên iOS, video không bao giờ được tải trước.
  • Khi chế độ Trình tiết kiệm dữ liệu được bật, preload sẽ được đặt thành none theo mặc định.

Vì các hành vi mặc định của trình duyệt liên quan đến preload không phải là hành vi cố định, nên có lẽ bạn nên cân nhắc rõ ràng nhất. Trong trường hợp này, khi 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ả 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. Tính năng 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 phát lại video trong JavaScript.

Thật không may, tính năng này không hữu ích khi bạn muốn sử dụng video thay cho ảnh GIF động, sẽ được đề cập đến trong phần tiếp theo.

Đối với video hoạt động dưới dạng ảnh GIF động thay thế

Mặc dù ảnh GIF động được sử dụng rộng rãi, nhưng ở một số khía cạnh, ảnh GIF động vẫn chưa tương đương với video tương đương, đặc biệt là ở kích thước tệp. Ảnh GIF động có thể kéo dài trong phạm vi vài megabyte dữ liệu. 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 ảnh GIF động không đơn giản như phần tử <img>. Ảnh GIF động có ba đặc điểm:

  1. Các quảng cáo này sẽ tự động phát khi được tải.
  2. Các API này lặp lại liên tục (mặc dù không phải lúc nào cũng đúng).
  3. Họ không có bản âm thanh.

Để thực hiện điều này với phần tử <video>, bạn sẽ thấy 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à phần tự giải thích. playsinline là cần thiết để tính năng tự động phát diễn ra trong iOS. Giờ đây, bạn đã có tính năng thay thế video dưới dạng GIF có thể sử dụng được trên nhiều nền tảng. Nhưng làm thế 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 có thêm 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 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 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 phần tử <video>, bạn cần lặp lại tất cả các phần tử con <source> và lật thuộc tính data-src của các phần tử đó thành các thuộc tính src. Sau khi hoàn tất, 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 phải 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 lớp này có hiệu suất cao, nhưng sẽ cần phải được chèn nhiều lần 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. Ứng dụng này cũng có thể tải từng phần hình ảnh video poster bằng cách sử dụ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 API này cung cấp một phương thức quen thuộc để tải từng phần hình ảnh cho những người đã quen 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 nhiều hoạt động tải từng phần của bạn.