Chrome DevTools JavaScript 콘솔에서 예기치 않은 미디어 오류를 발견하셨나요?
또는
그렇다면 잘 찾아오셨습니다. 걱정하지 마세요. 이러한 문제가 발생하는 이유와 해결 방법을 설명해 드리겠습니다.
원인
다음은 표시되는 'Uncaught (in promise)' 오류를 재현하는 JavaScript 코드입니다.
<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()
호출은 단일 결과를 비동기식으로 반환하는 함수인 Promise를 반환합니다. 재생이 성공하면 Promise가 처리되고 playing
이벤트가 동시에 실행됩니다. 재생에 실패하면 실패를 설명하는 오류 메시지와 함께 Promise가 거부됩니다.
다음과 같이 진행됩니다.
video.play()
가 동영상 콘텐츠를 비동기식으로 로드하기 시작합니다.video.pause()
: 동영상이 아직 준비되지 않았으므로 동영상 로드를 중단합니다.video.play()
가 비동기식으로 크게 거부합니다.
코드에서 동영상 재생 Promise를 처리하지 않으므로 Chrome DevTools에 오류 메시지가 표시됩니다.
해결 방법
이제 근본 원인을 파악했으므로 이 문제를 해결하기 위해 취할 수 있는 조치를 살펴보겠습니다.
먼저 미디어 요소 (동영상 또는 오디오)가 재생된다고 가정하지 마세요. play
함수에서 반환된 Promise를 확인하여 거부되었는지 확인합니다. 재생이 실제로 시작될 때까지 Promise가 처리되지 않는다는 점에 유의하세요. 즉, 미디어가 재생될 때까지 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()
약속은 결코 거부되지 않습니다. 유효한 소스가 없는 경우에만 발생합니다.