DOMException : la requête play() a été interrompue.

François Beaufort
François Beaufort

Avez-vous rencontré cette erreur multimédia inattendue dans la console JavaScript de Chrome DevTools ?

ou

Vous êtes au bon endroit. Ne vous inquiétez pas. Je vais vous expliquer pourquoi cela se produit et comment résoudre le problème.

Qu'est-ce qui cause ce problème ?

Vous trouverez ci-dessous du code JavaScript qui reproduit l'erreur "Non interceptée (dans la promesse)" que vous rencontrez:

À éviter
<video id="video" preload="none" src="https://example.com/file.mp4"></video>

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

Le code ci-dessus génère le message d'erreur suivant dans les outils pour les développeurs Chrome:

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

Étant donné que la vidéo n'est pas chargée en raison de preload="none", la lecture vidéo ne commence pas nécessairement immédiatement après l'exécution de video.play().

De plus, depuis Chrome 50, un appel play() sur un élément <video> ou <audio> renvoie une Promise, une fonction qui renvoie un seul résultat de manière asynchrone. Si la lecture aboutit, la promesse est remplie et l'événement playing est déclenché en même temps. Si la lecture échoue, la promesse est rejetée avec un message d'erreur expliquant l'échec.

Voici ce qui se passe:

  1. video.play() commence à charger le contenu vidéo de manière asynchrone.
  2. video.pause() interrompt le chargement de la vidéo, car elle n'est pas encore prête.
  3. video.play() rejette de manière asynchrone et bruyante.

Comme nous ne gérons pas la promesse de lecture de la vidéo dans notre code, un message d'erreur s'affiche dans les outils de développement Chrome.

Solution

Maintenant que nous avons identifié la cause du problème, voyons comment le résoudre.

Tout d'abord, ne partez jamais du principe qu'un élément multimédia (vidéo ou audio) sera lu. Examinez la promesse renvoyée par la fonction play pour voir si elle a été rejetée. Il est important de noter que la promesse ne sera pas remplie tant que la lecture n'a pas commencé, ce qui signifie que le code dans then() ne s'exécutera pas tant que le contenu multimédia n'est pas en cours de lecture.

À faire

Exemple: Lecture automatique

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

Exemple: Lecture et pause

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

C'est parfait pour cet exemple simple, mais que se passe-t-il si vous utilisez video.play() pour pouvoir lire une vidéo plus tard ?

Je vais te dire un secret. Vous n'êtes pas obligé d'utiliser video.play(). Vous pouvez utiliser video.load(). Voici comment procéder:

À faire

Exemple: Fetch & Play

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

Assistance concernant la promesse Play

Au moment de la rédaction de cet article, HTMLMediaElement.play() renvoie une promesse dans Chrome, Edge, Firefox, Opera et Safari.

Zone dangereuse

<source> dans <video> fait en sorte que la promesse play() ne soit jamais refusée

Pour <video src="not-existing-video.mp4"\>, la promesse play() est rejetée comme prévu, car la vidéo n'existe pas. Pour <video><source src="not-existing-video.mp4" type='video/mp4'></video>, la promesse play() n'est jamais refusée. Cela ne se produit que si aucune source valide n'est disponible.

Bug Chromium