Chrome DevTools で予期しないメディアエラーに遭遇しましたか? JavaScript コンソールを使用できますか?
または
君ならきっといるのよ。恐れる必要はありません。この問題の原因と修正方法をご説明いたします。
原因
以下は、「Unc catch (in Promise)」エラーを再現する JavaScript コードです。 以下のエラーが表示されます。
<video id="video" preload="none" src="https://example.com/file.mp4"></video> <script> video.play(); // <-- This is asynchronous! video.pause(); </script>
上記のコードを実行すると、Chrome DevTools で次のエラー メッセージが表示されます。
_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()
の場合は、非同期で大きな音が拒否されます。
コードでは動画再生の約束を処理していないため、エラー メッセージが表示されます。 Chrome DevTools に表示されます。
解決方法
根本原因がわかったところで、この問題を解決するために何ができるかを見ていきましょう。
まず、メディア要素(動画や音声)が再生されると想定しないでください。注目すべき点は、
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 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
拒否されることはありません。これは、有効なソースがない場合にのみ発生します。