Você acabou de se deparar com esse erro de mídia inesperado no Console JavaScript do Chrome DevTools?
ou
Você está no lugar certo. Não tenha medo. Vou explicar o que está causando esse problema e como corrigi-lo.
O que está causando isso
Veja o código JavaScript abaixo que reproduz o erro "Uncaught (in promise)" que está vendo:
<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
começa imediatamente após video.play()
ser executado.
Além disso, desde o Chrome 50, uma chamada play()
em um elemento <video>
ou <audio>
retorna uma Promise, uma função que retorna um único resultado
de forma assíncrona. Se a reprodução for bem-sucedida, a promessa será atendida e o
evento playing
será disparado 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 conteúdo de vídeo de forma assíncrona.- O
video.pause()
interrompe o carregamento do vídeo porque ele ainda não está pronto. - O
video.play()
rejeita em voz alta de maneira assíncrona.
Como não estamos processando a promessa de reprodução de vídeo no nosso código, uma mensagem de erro é exibida 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. Observe a promessa retornada pela função play
para ver se ela foi rejeitada. A
promessa não será atendida até que a reprodução seja
iniciada, o que significa que o código dentro do then()
não será executado até que a mídia
seja 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: reproduzir 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 esse exemplo simples, mas e se você usar video.play()
para
reproduzir um vídeo mais tarde?
Vou contar um segredo. Não é necessário usar video.play()
, você pode usar
video.load()
. Veja como fazer isso:
Exemplo: Buscar e jogar
<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 a promessas do Google Play
No momento em que este artigo foi escrito, HTMLMediaElement.play()
retornava uma promessa no Chrome, Edge, Firefox, Opera e Safari.
Zona de perigo
<source>
em <video>
faz com que a promessa de play()
nunca seja rejeitada.
Para <video src="not-existing-video.mp4"\>
, a promessa play()
é rejeitada conforme
esperado, já que 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 há fontes válidas.