DOMException: a solicitação play() foi interrompida

François Beaufort
François Beaufort

Você se deparou com um erro de mídia inesperado no Chrome DevTools? Console JavaScript?

ou

Você está no lugar certo. Não tenha medo. Vamos explicar o que está causando esse problema e como corrigir.

O que está causando isso

Veja um código JavaScript abaixo que reproduz a mensagem "Não capturado (em promessa)" erro que você está vendo:

O que não fazer
<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 carregou devido a preload="none", a reprodução não vai começar logo depois que video.play() for executado.

Além disso, desde o Chrome 50, uma chamada play() em uma <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 é atendida e o O evento playing é disparado ao mesmo tempo. Se a reprodução falhar, a promessa será rejeitado e uma mensagem de erro explicando a falha.

Aqui está o que está acontecendo:

  1. video.play() começa a carregar o conteúdo de vídeo de forma assíncrona.
  2. video.pause() interrompe o carregamento do vídeo porque ele ainda não está pronto.
  3. video.play() rejeita de forma assíncrona em volume alto.

Como não processamos 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, não presuma que um elemento de mídia (vídeo ou áudio) será reproduzido. Confira a promessa retornada pela função play para ver se ela foi rejeitada. É A promessa não será cumprida até que a reprodução iniciado, o que significa que o código dentro da then() não será executado até que a mídia está tocando.

O que fazer

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>
O que fazer

Exemplo: Play & 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 ser pode reproduzir um vídeo mais tarde?

Vou te contar um segredo. Não é necessário usar video.play(), você pode usar video.load(). Veja como fazer isso:

O que fazer

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 ao Play Commit

No momento da gravação, HTMLMediaElement.play() retorna uma promessa em Chrome, Edge, Firefox, Opera e Safari.

Zona de perigo

<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, pois o vídeo não existe. Para <video><source src="not-existing-video.mp4" type='video/mp4'></video>, a promessa play() nunca rejeita. Isso só acontece quando não há fontes válidas.

Bug do Chromium