DOMException - Permintaan play() terganggu

François Beaufort
François Beaufort

Apakah Anda baru saja menemukan {i>error<i} media yang tidak terduga di Chrome DevTools Konsol JavaScript?

atau

Anda berada di tempat yang tepat. Jangan takut. Saya akan menjelaskan penyebabnya dan cara memperbaikinya.

Apa penyebabnya

Berikut beberapa kode JavaScript di bawah ini yang mereproduksi error "Uncaught (in promise)" error yang Anda lihat:

Larangan
<video id="video" preload="none" src="https://example.com/file.mp4"></video>

<script>
  video.play(); // <-- This is asynchronous!
  video.pause();
</script>

Kode di atas menghasilkan pesan error ini di Chrome DevTools:

_Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().

Karena video tidak dimuat karena preload="none", pemutaran video tidak akan selalu dimulai segera setelah video.play() dieksekusi.

Selain itu, sejak Chrome 50, panggilan play() pada <video> atau <audio> menampilkan Promise, fungsi yang menampilkan satu hasil secara asinkron. Jika pemutaran berhasil, Promise akan terpenuhi dan Peristiwa playing diaktifkan secara bersamaan. Jika pemutaran gagal, Promise akan ditolak bersama dengan pesan {i>error<i} yang menjelaskan kegagalan itu.

Inilah yang terjadi:

  1. video.play() mulai memuat konten video secara asinkron.
  2. video.pause() mengganggu pemuatan video karena belum siap.
  3. video.play() menolak dengan keras secara asinkron.

Pesan error akan muncul karena kita tidak menangani Promise pemutaran video dalam kode muncul di Chrome DevTools.

Cara memperbaikinya

Setelah memahami akar masalahnya, mari kita lihat apa yang dapat kita lakukan untuk memperbaikinya.

Pertama, jangan pernah berasumsi elemen media (video atau audio) akan diputar. Lihat Promise yang ditampilkan oleh fungsi play untuk mengetahui apakah Promise ditolak. Penting perhatikan bahwa Promise tidak akan terpenuhi sampai pemutaran benar-benar dimulai, yang berarti kode di dalam then() tidak akan dieksekusi hingga media sedang diputar.

Anjuran

Contoh: Putar otomatis

<video id="video" preload="none" src="https://example.com/file.mp4"></video>

<script>
  // Show loading animation.
  var playPromise = video.play();

  if (playPromise !== undefined) {
    playPromise.then(_ => {
      // Automatic playback started!
      // Show playing UI.
    })
    .catch(error => {
      // Auto-play was prevented
      // Show paused UI.
    });
  }
</script>
Anjuran

Contoh: Putar & Jeda

<video id="video" preload="none" src="https://example.com/file.mp4"></video>
 
<script>
  // Show loading animation.
  var playPromise = video.play();
 
  if (playPromise !== undefined) {
    playPromise.then(_ => {
      // Automatic playback started!
      // Show playing UI.
      // We can now safely pause video...
      video.pause();
    })
    .catch(error => {
      // Auto-play was prevented
      // Show paused UI.
    });
  }
</script>

Itu adalah contoh sederhana yang bagus, tetapi bagaimana jika Anda menggunakan video.play() untuk bisa memutar video nanti?

Aku akan memberi tahumu sebuah rahasia. Anda tidak perlu menggunakan video.play(), Anda dapat menggunakan video.load() dan berikut ini caranya:

Anjuran

Contoh: Ambil & Mainkan

<video id="video"></video>
<button id="button"></button>

<script>
  button.addEventListener('click', onButtonClick);

  function onButtonClick() {
    // This will allow us to play video later...
    video.load();
    fetchVideoAndPlay();
  }

  function fetchVideoAndPlay() {
    fetch('https://example.com/file.mp4')
    .then(response => response.blob())
    .then(blob => {
      video.srcObject = blob;
      return video.play();
    })
    .then(_ => {
      // Video playback started ;)
    })
    .catch(e => {
      // Video playback failed ;(
    })
  }
</script>

Dukungan promise Play

Pada saat penulisan, HTMLMediaElement.play() menampilkan promise dalam Chrome, Edge, Firefox, Opera, dan Safari.

Zona bahaya

<source> dalam <video> membuat promise play() tidak pernah ditolak

Untuk <video src="not-existing-video.mp4"\>, promise play() akan ditolak sebagai seperti yang diharapkan karena video tidak ada. Untuk <video><source src="not-existing-video.mp4" type='video/mp4'></video>, promise play() tidak pernah menolak. Hal ini hanya terjadi jika tidak ada sumber yang valid.

Bug Chromium