DOMException - La richiesta play() è stata interrotta

François Beaufort
François Beaufort

Hai appena riscontrato questo errore multimediale imprevisto nella console JavaScript di Chrome DevTools?

o

Allora sei nel posto giusto. Non preoccuparti. Ti spiegherò cosa causa il problema e come risolverlo.

Qual è la causa

Di seguito è riportato un codice JavaScript che riproduce l'errore "Uncaught (in promise)" visualizzato:

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 viene caricato a causa di preload="none", la riproduzione non necessariamente inizia subito dopo l'esecuzione di preload="none".video.play()

Inoltre, a partire da Chrome 50, una chiamata play() a un elemento <video> o <audio> restituisce una promessa, una funzione che restituisce un singolo risultato in modo asincrono. Se la riproduzione va a buon fine, la promessa viene soddisfatta e contemporaneamente viene attivato l'evento playing. Se la riproduzione non va a buon fine, la promessa viene rifiutata insieme a un messaggio di errore che spiega il problema.

Ecco cosa succede:

  1. video.play() inizia a caricare i contenuti video in modo asincrono.
  2. video.pause() interrompe il caricamento del video perché non è ancora pronto.
  3. video.play() rifiuta in modo asincrono ad alto volume.

Poiché non gestiamo la promessa di riproduzione del video nel nostro codice, viene visualizzato un messaggio di errore in Chrome DevTools.

Come risolvere il problema

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

Innanzitutto, non dare mai per scontato che un elemento multimediale (video o audio) venga riprodotto. Controlla la promessa restituita dalla funzione play per vedere se è stata rifiutata. È importante notare che la promessa non verrà soddisfatta finché la riproduzione non sarà effettivamente iniziata, il che significa che il codice all'interno di then() non verrà eseguito finché i contenuti multimediali non saranno 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: Riproduzione e messa 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>

Perfetto per questo semplice esempio, ma cosa succede se utilizzi video.play() per poter riprodurre un video in un secondo momento?

Ti svelerò un segreto. Non devi utilizzare video.play(), puoi utilizzare video.load() ed ecco come:

Cosa fare

Esempio: Gioca e recupera

<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 per la promessa di Google Play

Al momento della stesura di questo articolo, HTMLMediaElement.play() restituisce una promessa in Chrome, Edge, Firefox, Opera e Safari.

Zona pericolosa

<source> in <video> fa sì che la promessa play() non venga mai rifiutata

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 viene mai rifiutata. Ciò si verifica solo se non sono presenti origini valide.

Bug di Chromium