Czy właśnie natrafiłeś/natrafiłaś na ten nieoczekiwany błąd multimediów w konsoli JavaScript w narzędziach deweloperskich w Chrome?
lub
Jesteś we właściwym miejscu. Bez obaw. Wyjaśnię, co jest tego przyczyną i jak to naprawić.
Co jest tego przyczyną
Poniżej znajduje się kod JavaScript, który odtwarza błąd „Uncaught (in promise)”:
<video id="video" preload="none" src="https://example.com/file.mp4"></video> <script> video.play(); // <-- This is asynchronous! video.pause(); </script>
Powyższy kod powoduje wyświetlenie tego komunikatu o błędzie w Narzędziach deweloperskich w Chrome:
_Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
Ponieważ film nie jest wczytywany z powodu preload="none"
, jego odtwarzanie niekoniecznie rozpocznie się natychmiast po wykonaniu video.play()
.
Ponadto od Chrome 50 wywołanie play()
elementu <video>
lub <audio>
zwraca obietnicę, czyli funkcję, która asynchronicznie zwraca pojedynczy wynik. Jeśli odtwarzanie się powiedzie, obietnica zostanie spełniona i wywołane zostanie zdarzenie playing
. Jeśli odtwarzanie się nie powiedzie, obietnica zostanie odrzucona, a wraz z tym pojawi się komunikat o błędzie wyjaśniający przyczynę odrzucenia.
Oto, co się dzieje:
video.play()
rozpoczyna asynchroniczne wczytywanie treści wideo.video.pause()
przerywa wczytywanie filmu, ponieważ nie jest on jeszcze gotowy.video.play()
odrzuca asynchronicznie głośno.
Ponieważ w naszym kodzie nie obsługujemy obietnicy odtwarzania filmu, w Chrome DevTools pojawia się komunikat o błędzie.
Jak to naprawić
Teraz, gdy znamy już główną przyczynę, zobaczmy, co możemy zrobić, aby rozwiązać ten problem.
Po pierwsze, nigdy nie zakładaj, że element multimedialny (wideo lub dźwięk) będzie odtwarzany. Sprawdź obietnicę zwróconą przez funkcję play
, aby zobaczyć, czy została odrzucona. Warto pamiętać, że obietnica nie zostanie spełniona, dopóki odtwarzanie nie rozpocznie się, co oznacza, że kod w then()
nie zostanie wykonany, dopóki media nie będą odtwarzane.
Przykład: automatyczne odtwarzanie
<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>
Przykład: odtwarzanie i wstrzymywanie
<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>
To świetne w przypadku tego prostego przykładu, ale co, jeśli chcesz odtworzyć film później?video.play()
Zdradzę Ci sekret. Nie musisz używać video.play()
, możesz użyć video.load()
. Oto jak to zrobić:
Przykład: Przynieś i odtwórz
<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>
Pomoc dotycząca Gwarancji Google Play
W momencie pisania tego artykułu funkcja HTMLMediaElement.play()
zwraca obietnicę w przeglądarkach Chrome, Edge, Firefox, Opera i Safari.
Strefa zagrożenia
<source>
w <video>
powoduje, że play()
promise nigdy nie odrzuca
W przypadku <video src="not-existing-video.mp4"\>
play()
obiecuje odrzucić zgłoszenie, ponieważ film nie istnieje. W przypadku <video><source
src="not-existing-video.mp4" type='video/mp4'></video>
play()
nigdy nie odrzuca obietnicy. Dzieje się tak tylko wtedy, gdy nie ma prawidłowych źródeł.