การโหลดวิดีโอแบบ Lazy Loading

เผยแพร่: 16 สิงหาคม 2019

คุณอาจต้องทำการโหลดวิดีโอแบบ Lazy Load ด้วยเช่นเดียวกับองค์ประกอบรูปภาพ โดยทั่วไปวิดีโอจะโหลดด้วยองค์ประกอบ <video> แต่สำหรับวิดีโอที่โฮสต์ในบริการอื่นๆ เช่น YouTube วิดีโอเหล่านั้นอาจใช้ <iframe> (ในกรณีนี้ โปรดดูบทความเกี่ยวกับ iframe แบบการโหลดแบบเลื่อน)

วิธีโหลด <video> แบบเลื่อนเวลาจะขึ้นอยู่กับกรณีการใช้งาน เนื่องจากมีโซลูชันที่แตกต่างกัน 2-3 รายการ

สำหรับวิดีโอที่ไม่เล่นอัตโนมัติ

โดยทั่วไปแล้ว แนวทางปฏิบัติแนะนำคือการหลีกเลี่ยงวิดีโอที่เล่นอัตโนมัติเนื่องจากจะปล่อยให้ผู้ใช้เป็นผู้ควบคุม ในกรณีเหล่านี้ การระบุแอตทริบิวต์ preload ในองค์ประกอบ <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>

ตัวอย่างก่อนหน้านี้ใช้แอตทริบิวต์ preload ที่มีค่า none เพื่อไม่ให้เบราว์เซอร์โหลดข้อมูลวิดีโอใดๆ ล่วงหน้า แอตทริบิวต์ poster จะให้ตัวยึดตําแหน่งแก่องค์ประกอบ <video> ซึ่งจะแสดงในพื้นที่นั้นขณะที่วิดีโอโหลด

ในเบราว์เซอร์ส่วนใหญ่ preload จะตั้งค่าเริ่มต้นเป็น metadata และระบบจะโหลดวิดีโอบางส่วนไว้ล่วงหน้าโดยใช้ส่วนหัว Content-Range ซึ่งอาจส่งผลให้มีการดาวน์โหลดข้อมูลมากกว่าที่ต้องการ โดยเฉพาะในกรณีที่เบราว์เซอร์ไม่รองรับส่วนหัว Content-Range แม้ว่าจะรองรับแล้ว แต่เบราว์เซอร์จะไม่ทราบตำแหน่งไบต์ที่จัดเก็บข้อมูลเมตา และข้อมูลเมตาอาจไม่ได้จัดเก็บไว้ที่ส่วนต้นของไฟล์ ดังนั้น วิธีที่ดีที่สุดในการหลีกเลี่ยงการโหลดวิดีโอคือการระบุ none และใช้ preload="none"

การดำเนินการนี้สามารถปรับปรุงเพิ่มเติมเพื่อโหลดข้อมูลเมตาล่วงหน้าเมื่อผู้ใช้วางเมาส์เหนือวิดีโอด้วยแอตทริบิวต์ onmouseenter (หรือด้วยตัวแฮนเดิลเหตุการณ์ mouseenter ที่เทียบเท่า)

<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>

วิธีนี้ไม่เพียงช่วยลดความล่าช้าเมื่อผู้ใช้เล่นวิดีโอเท่านั้น แต่ยังแสดงระยะเวลาของวิดีโอทันทีที่ผู้ใช้เปิดวิดีโอ

วิดีโอสามารถมีคุณสมบัติเป็นผู้สมัคร LCP รูปภาพ poster จะโหลดเร็วกว่าวิดีโอ ดังนั้นคุณควรใช้รูปภาพโปสเตอร์ในกรณีที่รูปภาพเป็น LCP ที่เป็นไปได้ แต่ก็ต้องโหลดรูปภาพล่วงหน้าด้วยค่าแอตทริบิวต์ 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>

สําหรับวิดีโอที่ทำหน้าที่แทน GIF แบบเคลื่อนไหว

วิดีโอที่เล่นอัตโนมัติมักใช้กับภาพเคลื่อนไหวแบบรวดเร็วสไตล์ GIF แม้ว่า GIF แบบเคลื่อนไหวจะได้รับความนิยมอย่างแพร่หลาย แต่ก็ยังด้อยกว่าวิดีโอที่เทียบเท่าในหลายๆ ด้าน โดยเฉพาะเรื่องขนาดไฟล์ GIF แบบเคลื่อนไหวอาจมีข้อมูลขนาดหลายเมกะไบต์ วิดีโอที่มีคุณภาพภาพใกล้เคียงกันมักจะมีขนาดเล็กกว่ามาก

การใช้องค์ประกอบ <video> แทน GIF ที่เป็นภาพเคลื่อนไหวนั้นไม่ตรงไปตรงมาเท่ากับองค์ประกอบ <img> GIF แบบเคลื่อนไหวมีลักษณะ 3 อย่างดังนี้

  1. วิดีโอจะเล่นโดยอัตโนมัติเมื่อโหลด
  2. โดยเล่นวนไปเรื่อยๆ (แต่ก็อาจไม่เสมอไป)
  3. วิดีโอไม่มีแทร็กเสียง

การทำเช่นนี้ด้วยองค์ประกอบ <video> จะมีลักษณะดังนี้

<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>

แอตทริบิวต์ autoplay, muted และ loop นั้นเข้าใจได้ทันที playsinline เป็นสิ่งจําเป็นเพื่อให้การเล่นอัตโนมัติเกิดขึ้นใน iOS ตอนนี้คุณมีวิดีโอที่เปลี่ยนเป็น GIF ที่ใช้งานได้แล้ว ซึ่งใช้ได้กับทุกแพลตฟอร์ม แต่การโหลดแบบ Lazy Loading นั้นทำอย่างไร ในการเริ่มต้น ให้แก้ไขมาร์กอัป <video> ดังนี้

<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>

คุณจะเห็นการเพิ่มแอตทริบิวต์ poster ซึ่งให้คุณระบุตัวยึดตําแหน่งเพื่อใช้พื้นที่ขององค์ประกอบ <video> จนกว่าระบบจะโหลดวิดีโอแบบ Lazy Load เช่นเดียวกับตัวอย่างการโหลดแบบเลื่อนเวลาของ <img> ให้เก็บ URL ของวิดีโอไว้ในแอตทริบิวต์ data-src ขององค์ประกอบ <source> แต่ละรายการ จากนั้นใช้โค้ด JavaScript ที่คล้ายกับตัวอย่างการโหลดแบบเลื่อนเวลาของภาพโดย 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);
    });
  }
});

เมื่อทำการโหลดแบบเลื่อนเวลาขององค์ประกอบ <video> คุณจะต้องวนดูองค์ประกอบย่อย <source> ทั้งหมดและเปลี่ยนแอตทริบิวต์ data-src เป็นแอตทริบิวต์ src เมื่อดำเนินการเสร็จแล้ว คุณต้องเรียกใช้การโหลดวิดีโอโดยเรียกใช้เมธอด load ขององค์ประกอบ จากนั้นสื่อจะเริ่มเล่นโดยอัตโนมัติตามแอตทริบิวต์ autoplay

เมื่อใช้วิธีนี้ คุณจะมีโซลูชันวิดีโอที่จำลองลักษณะการทำงานของ GIF แบบเคลื่อนไหว แต่ไม่ต้องใช้อินเทอร์เน็ตมากเท่ากับ GIF แบบเคลื่อนไหว และคุณจะโหลดเนื้อหาแบบ Lazy Load ได้

ไลบรารีการโหลดแบบ Lazy Loading

ไลบรารีต่อไปนี้จะช่วยคุณในการโหลดวิดีโอแบบ Lazy Load

  • vanilla-lazyload และ lozad.js เป็นตัวเลือกที่มีน้ำหนักเบามากซึ่งใช้ Intersection Observer เท่านั้น ด้วยเหตุนี้ ไลบรารีจึงมีประสิทธิภาพสูง แต่จะต้องใส่ Polyfill ก่อนจึงจะใช้ในเบราว์เซอร์รุ่นเก่าได้
  • yall.js เป็นไลบรารีที่ใช้ Intersection Observer และเปลี่ยนไปใช้ Event Handler นอกจากนี้ยังสามารถโหลดรูปภาพ poster ของวิดีโอแบบ Lazy Load โดยใช้แอตทริบิวต์ data-poster ได้ด้วย
  • หากต้องการใช้ไลบรารีการโหลดแบบเลื่อนเวลาเฉพาะ React คุณอาจพิจารณาใช้ react-lazyload แม้ว่าจะไม่ได้ใช้ Intersection Observer แต่ IntersectionObserver มีวิธีการโหลดรูปภาพแบบ Lazy Loading ที่คุ้นเคยสำหรับผู้ที่คุ้นเคยกับการพัฒนาแอปพลิเคชันด้วย React

ไลบรารีการโหลดแบบเลื่อนดูทีละรายการเหล่านี้มีเอกสารประกอบที่ชัดเจนพร้อมรูปแบบมาร์กอัปมากมายสำหรับการโหลดแบบเลื่อนดู