您剛剛發現 Chrome 開發人員工具 JavaScript 控制台發生非預期的媒體錯誤嗎?
或
您找對地方了。別擔心,我會說明造成這個問題的原因和修正方式。
造成這個情況的原因
以下 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,並同時觸發 playing
事件。如果播放失敗,系統會拒絕 Promise,並顯示說明失敗的錯誤訊息。
請按照下列步驟操作:
video.play()
會開始以非同步方式載入影片內容。video.pause()
因為尚未就緒,會中斷影片載入。video.play()
會以非同步方式拒絕拒絕。
由於我們無法在程式碼中處理影片播放 Promise,因此 Chrome 開發人員工具會顯示錯誤訊息。
修正方式
瞭解根本原因後,接著來看看該如何修正這個問題。
首先,不要假設媒體元素 (影片或音訊) 會播放。請查看 play
函式傳回的 Promise,確認要求是否遭到拒絕。請注意,要等到播放實際開始時,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 Commit 支援
撰寫本文時,HTMLMediaElement.play()
會在 Chrome、Edge、Firefox、Opera 和 Safari 中傳回承諾。
危險區域
<video>
中的 <source>
讓 play()
承諾不會拒絕
如果是 <video src="not-existing-video.mp4"\>
,play()
承諾會意外拒絕,因為影片不存在。如果是 <video><source
src="not-existing-video.mp4" type='video/mp4'></video>
,play()
承諾絕不會拒絕。只有在沒有有效來源時才會發生。