Google Web 更新(2017年6月):DOMException The play() request was interrupted

英文原文:DOMException: The play() request was interrupted


你是不是刚刚在Chrome浏览器的控制台Console里遇到了这个未预料的媒体错误?

Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().

或者

Uncaught (in promise) DOMException: The play() request was interrupted by a new load request.

不要怕, 下面就来解释错误的原因和解决方法。

错误原因

下面的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 开始, <video>或<audio>元素调用play() 方法将会返回一个Promise,一个异步返回单一结果的函数。如果播放成功执行,Promise 会执行(fulfilled),同时会触发媒体的playing事件。如果播放失败,Promise会被拒绝执行,并且返回错误信息阐述失败原因。

这个过程中发生了这些事情:

  1. video.play() 试图异步加载视频内容。
  2. video.pause() 中断视频加载,因为并没有真正的准备好播放。
  3. video.play() 显式地拒绝异步加载。

这时候因为我们没有在代码里对视频播放的Promise进行处理,所以Chrome控制台抛出一个错误。

提示:唤起 video.pause() 并不是中断视频的唯一途径。你可以用 video.load()video.src=” 完完全全地重置视频的播放状态,包括视频缓冲。

解决方法

现在我们了解了问题的根源,然后来看看如何解决。

首先,不要恣意的去播放网页中的媒体文件。查看 play 方法返回的Promise是否被拒绝执行。如果播放没有真正的开始,Promise不会有任何值,也不会往下执行,下面示例中 then() 里面的代码也不会执行。

示例:自动播放(Autoplay)

<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)和停止(Pause)

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

播放的promise支持

目前,在Chrome, Firefox, Opera, and Safari浏览器中 HTMLMediaElement.play() 可以返回promise。Edge还在研发中。

警告

包含在<video>里面的<source> 会让 play() 的 promise 永远不会拒绝

比如<video src=”not-existing-video.mp4″>, 如果视频不存在,play() promise 会拒绝执行. 而<video><source src=”not-existing-video.mp4″ type=’video/mp4′></video>中 play() promise 不会拒绝。这种情况只会在没有可用的资源文件时触发。

Chromium Bug

您的赞助将会支持作者创作及本站运维

发表评论


TOP