DOMException: Se interrumpió la solicitud play().

François Beaufort
François Beaufort

¿Te encontraste con este error multimedia inesperado en la Consola de JavaScript de las Herramientas para desarrolladores de Chrome?

o

Entonces, estás en el lugar correcto. No desespere. Te explicaré qué está causando este problema y cómo solucionarlo.

¿A qué se debe esto?

A continuación, se indica el código JavaScript que reproduce el error "Uncapture (in Promise)" que ves:

Qué no debes hacer
<video id="video" preload="none" src="https://example.com/file.mp4"></video>

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

El código anterior genera este mensaje de error en las Herramientas para desarrolladores de Chrome:

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

Como el video no se carga debido a preload="none", la reproducción de video no necesariamente comienza inmediatamente después de que se ejecuta video.play().

Además, a partir de Chrome 50, una llamada a play() en un elemento <video> o <audio> muestra un elemento Promise, una función que muestra un solo resultado de forma asíncrona. Si la reproducción se realiza correctamente, se cumple la promesa y se activa el evento playing al mismo tiempo. Si la reproducción falla, se rechaza la promesa junto con un mensaje de error que explica el error.

Esto es lo que sucede:

  1. video.play() comienza a cargar contenido de video de forma asíncrona.
  2. video.pause() interrumpe la carga del video porque aún no está listo.
  3. video.play() se rechaza de forma asíncrona y fuerte.

Como no estamos manejando la promesa de reproducción de video en nuestro código, aparece un mensaje de error en las Herramientas para desarrolladores de Chrome.

Cómo resolverlo

Ahora que comprendemos la causa raíz, veamos qué podemos hacer para corregir esto.

Primero, nunca des por sentado que se reproducirá un elemento multimedia (video o audio). Observa la promesa que muestra la función play para ver si se rechazó. Vale la pena señalar que la promesa no se cumplirá hasta que se inicie la reproducción, lo que significa que el código dentro de then() no se ejecutará hasta que se reproduzca el contenido multimedia.

Ejemplo: Reproducción automática

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

Ejemplo: Reproducir y pausar

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

Es excelente para este ejemplo simple, pero ¿qué sucede si usas video.play() para poder reproducir un video más tarde?

Te contaré un secreto. No es necesario que uses video.play(), puedes usar video.load() de la siguiente manera:

Ejemplo: Recuperar y reproducir

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

Compatibilidad con promesas de Play

Al momento de escribir, HTMLMediaElement.play() muestra una promesa en Chrome, Edge, Firefox, Opera y Safari.

Zona de peligro

<source> dentro de <video> hace que la promesa play() nunca se rechace.

En el caso de <video src="not-existing-video.mp4"\>, la promesa play() se rechaza según lo esperado, ya que el video no existe. Para <video><source src="not-existing-video.mp4" type='video/mp4'></video>, la promesa play() nunca se rechaza. Solo sucede si no hay fuentes válidas.

Error de Chromium