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

François Beaufort
François Beaufort

Czy właśnie natrafiłeś/natrafiłaś na ten nieoczekiwany błąd multimediów w konsoli JavaScript w narzędziach deweloperskich w Chrome?

lub

Jesteś we właściwym miejscu. Nie martw się. Wyjaśnię, co jest tego przyczynąjak to naprawić.

Co jest tego przyczyną

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

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 tego komunikatu o błędzie w Narzędziach deweloperskich w Chrome:

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

Ponieważ film nie jest wczytywany z powodu preload="none", jego odtwarzanie niekoniecznie rozpocznie się natychmiast po wykonaniu video.play().

Ponadto od wersji Chrome 50 wywołanie play() elementu <video> lub <audio> zwraca obietnicę (Promise), czyli funkcję, która asynchronicznie zwraca pojedynczy wynik. Jeśli odtwarzanie się powiedzie, obietnica zostanie spełniona i wywołane zostanie zdarzenie playing. Jeśli odtwarzanie się nie powiedzie, obietnica zostanie odrzucona, a wraz z tym pojawi się komunikat o błędzie wyjaśniający przyczynę odrzucenia.

Oto, co się dzieje:

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

Ponieważ w naszym kodzie nie obsługujemy obietnicy odtwarzania filmu, w Chrome DevTools pojawia się komunikat o błędzie.

Jak to naprawić

Teraz, gdy znamy już główną przyczynę, zobaczmy, co możemy zrobić, aby rozwiązać ten problem.

Po pierwsze, nigdy nie zakładaj, że element multimedialny (wideo lub dźwięk) będzie odtwarzany. Sprawdź obietnicę zwróconą przez funkcję play, aby zobaczyć, czy została odrzucona. Warto pamiętać, że obietnica nie zostanie spełniona, dopóki odtwarzanie nie rozpocznie się faktycznie, co oznacza, że kod w then() nie zostanie wykonany, dopóki media nie będą odtwarzane.

Tak

Przykład: automatyczne odtwarzanie

<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 świetne w przypadku tego prostego przykładu, ale co, jeśli chcesz odtworzyć film później?video.play()

Zdradzę Ci sekret. Nie musisz używać video.play(), możesz użyć video.load(). Oto jak to zrobić:

Tak

Przykład: Przynieś 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 Gwarancji Google Play

W momencie pisania tego artykułu funkcja HTMLMediaElement.play() zwraca obietnicę w przeglądarkach Chrome, Edge, Firefox, Opera i Safari.

Strefa zagrożenia

<source><video> powoduje, że play() promise nigdy nie odrzuca

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

Błąd w Chromium