DOMException - La richiesta play() è stata interrotta

François Beaufort
François Beaufort

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

o

Allora sei nel posto giusto. Non temere. Spiegherò la causa e come risolverlo.

Causa del problema

Di seguito è riportato il codice JavaScript che riproduce l'errore "Non rilevato (in promessa)" 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 per il seguente motivo: preload="none", la riproduzione del video non inizia necessariamente subito dopo l'esecuzione di video.play().

Inoltre, a partire da Chrome 50, una chiamata play() su un elemento <video> o <audio> restituisce una funzione Promise, che restituisce un singolo risultato in modo asincrono. Se la riproduzione ha esito positivo, la Promise viene soddisfatta e contemporaneamente l'evento playing viene attivato. Se la riproduzione non riesce, la funzionalità Promise viene rifiutata insieme a un messaggio di errore che spiega l'errore.

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 ad alta voce in modo asincrono.

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

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). Osserva la promessa restituita dalla funzione play per vedere se è stata rifiutata. Tieni presente che il programma Promise non sarà valido finché la riproduzione non sarà effettivamente avviata, quindi il codice all'interno di then() non verrà eseguito finché non è in corso la riproduzione dei contenuti multimediali.

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: Riproduci e metti 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>

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

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

Cosa fare

Esempio: Fetch & Play

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

Supporto Play promettente

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

Zona pericolosa

<source> in <video> fa una promessa di play() che non rifiuta 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 viene mai rifiutata. Ciò si verifica solo se non ci sono origini valide.

Bug di Chromium