נתקלתם בשגיאת המדיה הלא צפויה הזו במסוף JavaScript של DevTools ב-Chrome?
או
הגעת למקום הנכון. אל דאגה. אסביר מה גורם לכך ואיך לפתור את הבעיה.
מה גורם לכך
בהמשך מופיע קוד JavaScript שמייצר את השגיאה 'Uncaught (in promise)' שמוצגת לך:
<video id="video" preload="none" src="https://example.com/file.mp4"></video> <script> video.play(); // <-- This is asynchronous! video.pause(); </script>
הקוד שלמעלה גורם להצגת הודעת השגיאה הבאה בכלי הפיתוח ל-Chrome:
_Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
מכיוון שהסרטון לא נטען בגלל preload="none"
, ההפעלה של הסרטון לא תמיד מתחילה מיד אחרי ביצוע video.play()
.
בנוסף, החל מ-Chrome 50, קריאה ל-play()
על רכיב <video>
או <audio>
מחזירה Promise, פונקציה שמחזירה תוצאה אחת באופן אסינכרוני. אם ההפעלה מצליחה, ה-Promise מתקיים והאירוע playing
מופעל באותו הזמן. אם ההפעלה נכשלת, ה-Promise נדחה עם הודעת שגיאה שמסבירה את הכישלון.
זה מה שקורה:
video.play()
מתחיל לטעון תוכן וידאו באופן אסינכרוני.video.pause()
משבשת את טעינת הסרטון כי הוא עדיין לא מוכן.video.play()
דוחה באופן אסינכרוני בקול רם.
מכיוון שאנחנו לא מטפלים ב-Promise של הפעלת הסרטון בקוד שלנו, מוצגת הודעת שגיאה ב-Chrome DevTools.
איך לתקן אותה
עכשיו, אחרי שאנחנו מבינים את שורש הבעיה, נראה מה אפשר לעשות כדי לפתור אותה.
קודם כול, אף פעם אל תניחו שרכיב מדיה (וידאו או אודיו) יופעל. בודקים את ה-Promise שהוחזר על ידי הפונקציה play
כדי לראות אם הוא נדחה. חשוב לציין שה-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.
אזור מסוכן
<source>
בתוך <video>
גורם לכך שההבטחה של play()
לעולם לא תידחה
עבור <video src="not-existing-video.mp4"\>
, ההבטחה play()
נדחית כצפוי כי הסרטון לא קיים. עבור <video><source
src="not-existing-video.mp4" type='video/mp4'></video>
, ההבטחה של play()
אף פעם לא נדחית. זה קורה רק אם אין מקורות תקינים.