DOMException - درخواست play() قطع شد

فرانسوا بوفور
François Beaufort

آیا به‌تازگی با این خطای رسانه غیرمنتظره در کنسول جاوا اسکریپت Chrome DevTools مواجه شدید؟

یا

اونوقت تو جای درستی هستی ترس نداشته باش من توضیح خواهم داد که چه چیزی باعث این شده است و چگونه آن را برطرف کنم .

دلیلش چی است

در اینجا تعدادی کد جاوا اسکریپت در زیر آمده است که خطای "Uncaught (in premted)" را که مشاهده می کنید بازتولید می کند:

نکن
<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 ، یک فراخوان play() روی یک عنصر <video> یا <audio> یک Promise را برمی‌گرداند، تابعی که یک نتیجه را به صورت ناهمزمان برمی‌گرداند. در صورت موفقیت آمیز بودن پخش، Promise محقق می شود و رویداد playing همزمان اجرا می شود. اگر پخش ناموفق باشد، Promise به همراه یک پیام خطایی که خرابی را توضیح می دهد رد می شود.

حالا این چیزی است که اتفاق می افتد:

  1. video.play() شروع به بارگیری محتوای ویدیویی به صورت ناهمزمان می کند.
  2. video.pause() بارگیری ویدیو را قطع می کند زیرا هنوز آماده نیست.
  3. video.play() به صورت ناهمزمان با صدای بلند رد می کند.

از آنجایی که ما از پخش ویدیوی Promise در کد خود استفاده نمی کنیم، یک پیام خطا در ابزار توسعه کروم ظاهر می شود.

چطوری میشه اینو تعمیر کرد

اکنون که علت اصلی را فهمیدیم، بیایید ببینیم برای رفع آن چه کاری می توانیم انجام دهیم.

اول، هرگز فرض نکنید که یک عنصر رسانه (ویدئو یا صدا) پخش می شود. به 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() استفاده کنید و در اینجا نحوه انجام این کار آمده است:

انجام دادن

مثال: 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>

پشتیبانی از قول بازی

در زمان نوشتن، HTMLMediaElement.play() یک وعده را در کروم ، اج، فایرفاکس، اپرا و سافاری برمی‌گرداند.

منطقه خطر

<source> در <video> باعث می‌شود play() هرگز رد نشود

برای <video src="not-existing-video.mp4"\> ، وعده play() همانطور که انتظار می رود رد می شود زیرا ویدیو وجود ندارد. برای <video><source src="not-existing-video.mp4" type='video/mp4'></video> ، وعده play() هرگز رد نمی شود. فقط در صورتی اتفاق می افتد که منابع معتبری وجود نداشته باشد.

اشکال کروم