DOMWyjątki - Żądanie play() zostało przerwane

François Beaufort
François Beaufort

Czy właśnie natknął się na ten nieoczekiwany błąd multimediów w konsoli JavaScript Narzędzi deweloperskich w Chrome?

lub

Jesteś we właściwym miejscu. Bez obaw. Poniżej wyjaśniam, co powoduje ten problem i jak go rozwiązać.

Co jest tego przyczyną

Poniżej znajduje się kod JavaScript, który odtwarza błąd „Uncaught (w obietnicy)”:

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

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

Powyższy kod powoduje wyświetlenie w Narzędziach deweloperskich w Chrome tego komunikatu o błędzie:

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

Film nie został wczytany z powodu błędu preload="none", dlatego jego odtwarzanie nie rozpoczyna się od razu po wykonaniu video.play().

Co więcej, od Chrome 50 wywołanie play() w elemencie <video> lub <audio> zwraca Promise – funkcję, która asynchronicznie zwraca pojedynczy wynik. Jeśli odtwarzanie się powiedzie, obietnica zostanie zrealizowana, a zdarzenie playing zostanie uruchomione w tym samym czasie. W przypadku niepowodzenia odtwarzania obietnica jest odrzucana wraz z komunikatem o błędzie.

Co się teraz dzieje:

  1. video.play() zaczyna asynchronicznie wczytywać treści wideo.
  2. video.pause() przerywa wczytywanie filmu, ponieważ nie jest on jeszcze gotowy.
  3. video.play() odrzuca asynchronicznie głośno.

Ponieważ nasz kod nie obsługuje obietnicy odtworzenia filmu, w Narzędziach deweloperskich w Chrome pojawia się komunikat o błędzie.

Jak to naprawić

Znasz już przyczynę tego problemu. Teraz zobaczmy, co możemy zrobić, aby rozwiązać ten problem.

Po pierwsze, nigdy nie zakładaj, że element multimedialny (film lub dźwięk) zostanie odtworzony. Sprawdź obietnicę zwrócony przez funkcję play, aby sprawdzić, czy została odrzucona. Warto zauważyć, że obietnica nie zostanie zrealizowana, dopóki nie rozpocznie się odtwarzanie. Oznacza to, że kod zawarty w komponencie then() nie zostanie wykonany, dopóki multimedia nie zostaną odtworzone.

Tak

Przykład: autoodtwarzanie

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

Przykład: odtwarzanie i wstrzymywanie

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

To świetnie sprawdza się w przypadku tego prostego przykładu, ale co jeśli użyjesz funkcji video.play(), która pozwala odtworzyć film później?

Zdradzę Ci sekret. Nie musisz używać usługi video.play(). Możesz użyć aplikacji video.load(). Oto jak to zrobić:

Tak

Przykład: Pobierz i zagraj

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

Pomoc dotycząca oferty Google Play

W momencie napisania tekstu HTMLMediaElement.play() zwraca obietnicę w Chrome, Edge, Firefox, Opera i Safari.

Strefa zagrożenia

<source> w <video> zawiera play() obietnicę nigdy nie odrzuca

W przypadku <video src="not-existing-video.mp4"\> obietnica play() jest odrzucana zgodnie z oczekiwaniami, ponieważ film nie istnieje. W przypadku <video><source src="not-existing-video.mp4" type='video/mp4'></video> obietnica play() nigdy nie odrzuca. Dzieje się tak tylko wtedy, gdy nie ma prawidłowych źródeł.

Błąd Chromium