【问题标题】:HTML5 video.play returning Pending promisesHTML5 video.play 返回待处理的承诺
【发布时间】:2016-12-22 23:40:42
【问题描述】:

我正在尝试确定浏览器是否支持加载时自动播放。

我正在使用以下代码,它在 Android chrome 上运行良好,但对于桌面 Chrome,.catch 或 .then 中的任何行都没有被执行。承诺似乎只是无限期地返回待处理的承诺。

这是一个实际的 Chrome 错误还是我不明白 Promise 在这里是如何工作的?

const promise = document.createElement('video').play();

if (promise instanceof Promise) {
	promise.catch((error) => {
		// Check if it is the right error
		if (error.name === 'NotAllowedError') {
			autoPlayAllowed = false;
		} else {
			throw error;
		}
	}).then(() => {
		if (autoPlayAllowed) {
			// Autoplay is allowed - continue with initialization
			console.log('autoplay allowed')
		} else {
			// Autoplay is not allowed - wait for the user to trigger the play button manually
			console.log('autoplay NOT allowed')
		}
	});

} else {
	// Unknown if allowed
	console.log('autoplay unknown')
}

谢谢!

【问题讨论】:

  • 你从来没有为你的视频设置一个 src 吗?你预计会出现什么样的错误?
  • 感谢@Kaiido 的回复,我添加 src 后似乎也得到了相同的结果,我是否还缺少其他内容? var test = document.createElement('video'); test.setAttribute("src", "vjs.zencdn.net/v/oceans.mp4"); var promise = test.play(); ...(与有问题的代码相同)结果:Promise {[[PromiseStatus]]: "pending", [[PromiseValue ]]: 未定义}
  • 这真的很奇怪。关于定义 autoPlayAllowed 的好发现,有了它我至少可以从函数中返回一些值(并且.catch 似乎在 Android Chrome 上成功捕获了错误,这正是我所需要的)

标签: javascript google-chrome promise html5-video


【解决方案1】:

哪些浏览器 Promisify MediaElement.play()

WHATWG 规范仅建议在 2016 年 2 月 pull request 之后对 2016 年 1 月提交的 issue 进行 Promisified MediaElement.play()。这与最近阻止 MediaElements 自动播放的决定有关(除非在特殊情况下,例如these, for iOS Safari)。

W3C spec 仍然(截至 2017 年 11 月)似乎没有提到 MediaElement.play() 应该返回一个 Promise。

MediaElement.play() 返回 Promise 的版本:

Edge 的此更改状态为 unknown(请随意评论)

如何测试我的浏览器是否支持?

Chrome 团队已经发布了一个test page 来检查你自己的浏览器是否支持 Promisified MediaElement.play()

如果支持,日志框会显示:

Attempting to play automatically...
The play() Promise fulfilled! Rock on!

否则,它只会打印这两个的第一行。

我应该如何普遍支持MediaElement.play()

以下是Jeff Posnick 在 Google 开发者博客文章中推荐的最佳做法。在WebKit blog postBitMovin 中推荐了类似的代码,它们都源自原始的issue 文件。

var playPromise = document.querySelector('video').play();

// In browsers that don’t yet support this functionality,
// playPromise won’t be defined.
if (playPromise !== undefined) {
  playPromise.then(function() {
    // Automatic playback started!
  }).catch(function(error) {
    // Automatic playback failed.
    // Show a UI element to let the user manually start playback.
  });
}

基本上:存储调用MediaElement.play() 的结果,并且仅在结果未定义(例如object 类型)时将其作为Promise 链执行。

【讨论】:

    【解决方案2】:

    我不确定这是否是错误,但您需要为您的视频设置src,然后才能履行或拒绝播放承诺。

    将其设置为空字符串 "" 将引发“未找到支持的源”错误,但由于在您的原始代码中引发了无法识别的错误,因此 then 从未触发。 因此,您可以依靠此“未找到错误”来判断自动播放是否有效,或者不要抛出错误以转到 then。

    let autoPlayAllowed = true;
    let v = document.createElement('video');
    v.src = ""; // we need this
    
    const promise = v.play();
    
    if (promise instanceof Promise) {
      promise.catch(function(error) {
        console.log(error.message);
        // Check if it is the right error
        if (error.name === 'NotAllowedError') {
          autoPlayAllowed = false;
        } else {
          // Don't throw the error so that we get to the then
          // or throw it but set the autoPlayAllowed to true in here
        }
      }).then(function() {
        if (autoPlayAllowed) {
          // Autoplay is allowed - continue with initialization
          console.log('autoplay allowed')
        } else {
          // Autoplay is not allowed - wait for the user to trigger the play button manually
          console.log('autoplay NOT allowed')
        }
      });
    
    } else {
      // Unknown if allowed
      // Note: you could fallback to simple event listeners in this case
      console.log('autoplay unknown')
    }

    请注意,只有 WHATWG 规范包含了 MediaElement.play() 中的承诺,W3C 没有。因此,您可能希望回退到简单的事件侦听器,至少目前是这样。

    【讨论】:

      猜你喜欢
      • 2020-12-18
      • 2021-07-22
      • 2020-12-20
      • 1970-01-01
      • 2017-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多