DOMException - La richiesta play() è stata interrotta

François Beaufort
François Beaufort

Ti sei appena imbattuto in questo errore multimediale imprevisto in Chrome DevTools Console JavaScript?

o

Allora sei nel posto giusto. Non temere. Ti spiegheremo la causa e come risolvere il problema.

Causa

Di seguito è riportato del codice JavaScript che riproduce il messaggio "Uncaught (in Promessa)" che ricevi:

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

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

Il codice riportato sopra genera questo messaggio di errore in Chrome DevTools:

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

Poiché il video non è stato caricato a causa dell'errore preload="none", la riproduzione del video non iniziano necessariamente subito dopo l'esecuzione di video.play().

Inoltre, a partire da Chrome 50, una chiamata play() su un dispositivo <video> o <audio> restituisce una funzione Promise, ovvero una funzione che restituisce un singolo risultato in modo asincrono. Se la riproduzione va a buon fine, la Promessa viene rispettata e le playing evento viene attivato contemporaneamente. Se la riproduzione non va a buon fine, la Promessa viene viene rifiutata insieme a un messaggio che spiega l'errore.

Ecco cosa sta succedendo:

  1. video.play() avvia il caricamento dei contenuti video in modo asincrono.
  2. video.pause() interrompe il caricamento del video perché non è ancora pronto.
  3. video.play() rifiuta in modo asincrono.

Dal momento che non gestiamo la riproduzione del video Promise nel nostro codice, viene visualizzato un messaggio di errore viene visualizzato in Chrome DevTools.

Come risolvere il problema

Ora che abbiamo capito la causa principale, vediamo cosa possiamo fare per risolvere il problema.

Innanzitutto, non dare per scontato che venga riprodotto un elemento multimediale (video o audio). Guarda la promessa restituita dalla funzione play per vedere se è stata rifiutata. È vale la pena notare che la Promessa non si completa finché la riproduzione avviato, il che significa che il codice all'interno di then() non verrà eseguito fino a quando è in riproduzione.

Cosa fare

Esempio: riproduzione automatica

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

Esempio: Play & Mettere in pausa

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

Questo è ottimo per questo semplice esempio, ma cosa succede se usi video.play() per in grado di riprodurre un video in un secondo momento?

Ti dirò un segreto. Non è necessario utilizzare video.play(), puoi usare video.load() ed ecco come fare:

Cosa fare

Esempio: Recupera e Riproduzione

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

Assistenza nelle promesse di Google Play

Al momento della scrittura, HTMLMediaElement.play() restituisce una promessa in Chrome, Edge, Firefox, Opera e Safari.

Zona pericolosa

<source> in <video> fa la promessa di play() non rifiutare mai

Per <video src="not-existing-video.mp4"\>, la promessa play() viene rifiutata come previsto perché il video non esiste. Per <video><source src="not-existing-video.mp4" type='video/mp4'></video>, la promessa play() non rifiuta mai. Questo accade solo se non ci sono fonti valide.

Bug di Chromium