DOMException - تمت مقاطعة طلب play()

François Beaufort
François Beaufort

هل صادفت للتو هذا الخطأ غير المتوقع في الوسائط في "أدوات مطوري البرامج في Chrome" JavaScript Console؟

أو

أنت في المكان الصحيح إذًا. لا تقلق. وسأشرح لك سبب حدوث ذلك وكيفية حلّ المشكلة.

سبب ذلك

في ما يلي بعض رموز JavaScript التي تُعيد إنتاج الخطأ "لم يتم اكتشافه (في وعد)" الخطأ الذي يظهر لك:

الإجراءات غير المُوصى بها
<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، وهو دالة تُرجع نتيجة واحدة بشكل غير متزامن. فإذا نجح التشغيل، يتم تنفيذ الوعد يتم تنشيط حدث واحد (playing) في الوقت نفسه. في حال تعذُّر التشغيل، يكون الوعد هو مع ظهور رسالة خطأ تشرح الفشل.

إليك ما يحدث الآن:

  1. يبدأ video.play() في تحميل محتوى الفيديو بشكل غير متزامن.
  2. تتم مقاطعة تحميل الفيديو من قِبل "video.pause()" لأنّه ليس جاهزًا بعد.
  3. يجري video.play() الرفض بصوت عالٍ بشكل غير متزامن.

تظهر رسالة خطأ لأنّنا لا نعمل على معالجة فيديو Promise في الرمز البرمجي الخاص بنا تظهر في "أدوات مطوري البرامج في Chrome".

كيفية حلها

والآن بعد أن فهمنا السبب الجذري، لنرَ ما يمكننا فعله لإصلاح هذه المشكلة.

أولاً، لا تفترض أبدًا أنه سيتم تشغيل عنصر وسائط (فيديو أو صوت). انظر إلى الوعد الذي عرضته الدالة 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>
الإجراءات الموصى بها

مثال: Play & إيقاف مؤقَّت

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

منطقة خطرة

يتم رفض وعد "play()" من قِبل "<source>" ضمن <video>.

بالنسبة إلى <video src="not-existing-video.mp4"\>، يتم رفض الوعد play() باعتباره متوقع نظرًا لعدم وجود الفيديو. يمكنك تقديم وعد play() مقابل <video><source src="not-existing-video.mp4" type='video/mp4'></video>. لا يرفض أبدًا. ويحدث ذلك فقط في حال عدم توفّر مصادر صالحة.

خطأ Chromium