DOMException - play() 요청이 중단되었습니다.

François Beaufort
François Beaufort

Chrome DevTools 자바스크립트 콘솔에서 이 예상치 못한 미디어 오류를 발견하셨나요?

또는

잘 찾아오신 것입니다. 걱정하지 마십시오. 원인해결 방법에 대해 설명해 드리겠습니다.

원인

다음은 표시되는 '확인되지 않음 (프로미스에서)' 오류를 재현하는 자바스크립트 코드입니다.

금지사항
<video id="video" preload="none" src="https://example.com/file.mp4"></video>

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

위 코드를 실행하면 Chrome DevTools에 다음 오류 메시지가 표시됩니다.

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

preload="none"로 인해 동영상이 로드되지 않으므로 video.play()가 실행된 직후에 동영상 재생이 시작되지는 않습니다.

또한 Chrome 50부터 <video> 또는 <audio> 요소에 관한 play() 호출은 단일 결과를 비동기식으로 반환하는 함수인 프로미스를 반환합니다. 재생이 성공하면 프로미스가 처리되고 playing 이벤트가 동시에 실행됩니다. 재생이 실패하면 프로미스가 거부되고 실패를 설명하는 오류 메시지가 표시됩니다.

이제 다음과 같이 진행됩니다.

  1. video.play()가 동영상 콘텐츠 로드를 비동기식으로 시작합니다.
  2. video.pause()는 아직 동영상이 준비되지 않았으므로 동영상 로드를 중단합니다.
  3. video.play()는 비동기식으로 큰 소리로 거부합니다.

코드에서 동영상 재생 Promise를 처리하지 않으므로 Chrome DevTools에 오류 메시지가 표시됩니다.

해결 방법

이제 근본 원인을 파악했으니 이를 해결하기 위해 무엇을 할 수 있는지 알아보겠습니다.

첫째, 미디어 요소 (동영상 또는 오디오)가 재생될 것이라고 가정하지 마세요. play 함수에서 반환된 프로미스를 보고 거부되었는지 확인합니다. 프로미스는 재생이 실제로 시작될 때까지 처리하지 않는다는 점에 유의해야 합니다. 즉, then() 내부의 코드는 미디어가 재생될 때까지 실행되지 않습니다.

의견을 제시하지

예: 자동재생

<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>
의견을 제시하지

예: 재생 및 일시중지

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

이 간단한 예에서는 적합하지만 나중에 동영상을 재생할 수 있도록 video.play()를 사용하는 경우에는 어떻게 해야 할까요?

비밀을 알려드리겠습니다. video.play()를 사용할 필요는 없으며 video.load()를 사용하면 됩니다. 방법은 다음과 같습니다.

의견을 제시하지

예: 가져오기 및 재생

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

Play 약속 지원

작성 시점에 HTMLMediaElement.play()Chrome, Edge, Firefox, Opera, Safari에서 프로미스를 반환합니다.

위험 영역

<video> 내의 <source>play() 프로미스를 거부하지 않도록 합니다.

<video src="not-existing-video.mp4"\>의 경우 동영상이 없으므로 play() 프로미스가 예상대로 거부됩니다. <video><source src="not-existing-video.mp4" type='video/mp4'></video>의 경우 play() 프로미스가 거부되지 않습니다. 유효한 소스가 없는 경우에만 발생합니다.

Chromium 버그