¿Acabas de encontrar este error de contenido multimedia inesperado en la Consola de JavaScript de las Herramientas para desarrolladores de Chrome?
o
Entonces, estás en el lugar correcto. No te preocupes. Te explicaré qué lo causa y cómo solucionarlo.
Qué causa esto
A continuación, se muestra un código de JavaScript que reproduce el error "Uncaught (in promise)" que ves:
<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 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 comienza necesariamente inmediatamente después de que se ejecuta video.play()
.
Además, desde Chrome 50, una llamada play()
en un elemento <video>
o <audio>
muestra una promesa, 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 la falla.
Esto es lo que sucede:
video.play()
comienza a cargar contenido de video de forma asíncrona.video.pause()
interrumpe la carga del video porque aún no está listo.video.play()
rechaza de forma asíncrona de forma escandalosa.
Como no controlamos 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 solucionar este problema.
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: Autoplay
<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>
Eso es excelente para este ejemplo simple, pero ¿qué sucede si usas video.play()
para poder reproducir un video más adelante?
Te contaré un secreto. No es necesario que uses video.play()
, puedes usar video.load()
. Sigue estos pasos:
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 las promesas de Play
En el momento de escribir este artículo, HTMLMediaElement.play()
muestra una promesa en Chrome, Edge, Firefox, Opera y Safari.
Zona de peligro
<source>
dentro de <video>
hace que la promesa de play()
nunca se rechace.
Para <video src="not-existing-video.mp4"\>
, la promesa de play()
se rechaza como se espera, 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.