英文原文: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会被拒绝执行,并且返回错误信息阐述失败原因。
这个过程中发生了这些事情:
- video.play() 试图异步加载视频内容。
- video.pause() 中断视频加载,因为并没有真正的准备好播放。
- 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 不会拒绝。这种情况只会在没有可用的资源文件时触发。
您的赞助将会支持作者创作及本站运维
发表评论