Você acabou de encontrar esse erro de mídia inesperado no console JavaScript do Chrome DevTools?
ou
Então você está no lugar certo. Não se preocupe. Vou explicar o que está causando isso e como corrigir.
O que está causando isso?
Confira abaixo um código JavaScript que reproduz o erro "Uncaught (in promise)" que você está recebendo:
<video id="video" preload="none" src="https://example.com/file.mp4"></video> <script> video.play(); // <-- This is asynchronous! video.pause(); </script>
O código acima resulta nesta mensagem de erro no Chrome DevTools:
_Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
Como o vídeo não é carregado devido a preload="none"
, a reprodução não
necessariamente começa imediatamente após a execução de video.play()
.
Além disso, desde o Chrome 50, uma chamada play()
em um elemento <video>
ou <audio>
retorna uma promessa, uma função que retorna um único resultado
de forma assíncrona. Se a reprodução for bem-sucedida, a promessa será cumprida e o
evento playing
será acionado ao mesmo tempo. Se a reprodução falhar, a promessa será
rejeitada com uma mensagem de erro explicando a falha.
Veja o que está acontecendo:
video.play()
começa a carregar o conteúdo do vídeo de forma assíncrona.video.pause()
interrompe o carregamento do vídeo porque ele ainda não está pronto.video.play()
rejeita de forma assíncrona e com som.
Como não estamos processando a promessa de reprodução de vídeo no código, uma mensagem de erro aparece no Chrome DevTools.
Como corrigir o problema
Agora que entendemos a causa raiz, vamos ver o que podemos fazer para corrigir isso.
Primeiro, nunca presuma que um elemento de mídia (vídeo ou áudio) será reproduzido. Confira
a promessa retornada pela função play
para saber se ela foi rejeitada. Vale
observar que a promessa não será cumprida até que a reprodução seja realmente
iniciada, o que significa que o código dentro do then()
não será executado até que a mídia
esteja sendo reproduzida.
Exemplo: reprodução 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>
Exemplo: Abrir e 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>
Isso é ótimo para este exemplo simples, mas e se você usar video.play()
para
reproduzir um vídeo mais tarde?
Vou contar um segredo para você. Não é necessário usar video.play()
. Você pode usar
video.load()
, e aqui está como:
Exemplo: Buscar e reproduzir
<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>
Suporte à promessa do Google Play
No momento da escrita, HTMLMediaElement.play()
retorna uma promessa no
Chrome, Edge, Firefox, Opera e Safari.
Área perigosa
<source>
em <video>
faz com que a promessa play()
nunca seja rejeitada
Para <video src="not-existing-video.mp4"\>
, a promessa play()
é rejeitada como
esperado, porque o vídeo não existe. Para <video><source
src="not-existing-video.mp4" type='video/mp4'></video>
, a promessa play()
nunca é rejeitada. Isso só acontece se não houver fontes válidas.