您是否刚刚在 Chrome 开发者工具中偶然发现了这个意外的媒体错误 JavaScript 控制台?
或
那您就来对地方了。不必担心。我们将说明导致此问题的原因以及解决方法。
导致此问题的原因
下面的一些 JavaScript 代码可重现“未捕获(在 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 已执行,并且
同时触发了 playing
事件。如果播放失败,promise
以及说明失败的错误消息。
现在发生了以下情况:
video.play()
开始异步加载视频内容。video.pause()
会中断视频加载,因为视频尚未准备就绪。video.play()
大声拒绝。
由于我们在代码中不处理视频播放 Promise,因此系统会在 显示在 Chrome 开发者工具中。
解决方法
至此,我们已经了解了根本原因,下面我们来看看如何解决此问题。
首先,不要假定会播放媒体元素(视频或音频)。查看
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 promise 支持
在编写时,HTMLMediaElement.play()
会返回一个 promise
Chrome、Edge、Firefox、Opera 和 Safari。
危险区域
<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
绝不拒绝。只有在没有有效来源时才会出现这种情况。