Bạn vừa bắt gặp lỗi phương tiện không mong muốn này trong Công cụ của Chrome cho nhà phát triển Bảng điều khiển JavaScript không?
hoặc
Vậy là bạn đã đến đúng chỗ rồi. Không phải sợ hãi. Tôi sẽ giải thích nguyên nhân gây ra vấn đề này và cách khắc phục.
Nguyên nhân gây ra vấn đề này
Dưới đây là một số mã JavaScript bên dưới tái tạo lỗi "Chưa nắm bắt (trong lời hứa)" mà bạn đang gặp phải:
<video id="video" preload="none" src="https://example.com/file.mp4"></video> <script> video.play(); // <-- This is asynchronous! video.pause(); </script>
Mã ở trên dẫn đến thông báo lỗi này trong Công cụ của Chrome cho nhà phát triển:
_Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause().
Vì video không được tải do preload="none"
, nên tính năng phát lại video sẽ không
nhất thiết phải bắt đầu ngay sau khi video.play()
được thực thi.
Hơn nữa kể từ Chrome 50, một lệnh gọi play()
trên <video>
hoặc <audio>
phần tử trả về Promise, hàm trả về một kết quả duy nhất
một cách không đồng bộ. Nếu phát thành công, Lời hứa được thực hiện và
playing
sự kiện được kích hoạt cùng một lúc. Nếu không phát được, Promise sẽ
bị từ chối cùng với thông báo lỗi giải thích lỗi.
Bây giờ là những gì đang diễn ra:
video.play()
bắt đầu tải nội dung video không đồng bộ.video.pause()
làm gián đoạn quá trình tải video do video chưa sẵn sàng.video.play()
từ chối lớn không đồng bộ.
Vì chúng ta không xử lý video Promise (Lời hứa trong đoạn mã) nên sẽ xuất hiện một thông báo lỗi sẽ xuất hiện trong Công cụ của Chrome cho nhà phát triển.
Cách khắc phục
Giờ đây, khi đã hiểu được nguyên nhân gốc rễ, hãy cùng xem chúng ta có thể làm gì để khắc phục tình trạng này.
Trước tiên, đừng bao giờ giả định rằng một thành phần đa phương tiện (video hoặc âm thanh) sẽ phát. Xem
Promise được hàm play
trả về để xem liệu hàm này có bị từ chối hay không. Đó là
đáng chú ý là Lời hứa sẽ không thực hiện được cho đến khi quá trình phát lại thực sự
bắt đầu, nghĩa là mã bên trong then()
sẽ không thực thi cho đến khi phương tiện
đang phát.
Ví dụ: Tự động phát
<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>
Ví dụ: Chơi & Tạm dừng
<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>
Thật tuyệt vời cho ví dụ đơn giản này, nhưng nếu bạn sử dụng video.play()
làm
có thể phát video sau không?
Tôi sẽ cho bạn biết một bí mật. Bạn không phải sử dụng video.play()
, bạn có thể sử dụng
video.load()
và cách thực hiện như sau:
Ví dụ: Tìm nạp và Chơi
<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>
Hỗ trợ Play Promise
Tại thời điểm viết bài, HTMLMediaElement.play()
trả về lời hứa sau
Chrome, Edge, Firefox, Opera và Safari.
Vùng nguy hiểm
<source>
trong <video>
giúp play()
lời hứa không bao giờ từ chối
Đối với <video src="not-existing-video.mp4"\>
, lời hứa play()
sẽ từ chối dưới dạng
đúng như dự kiến vì video không tồn tại. Đối với <video><source
src="not-existing-video.mp4" type='video/mp4'></video>
, lời hứa play()
không bao giờ từ chối. Trường hợp này chỉ xảy ra nếu không có nguồn hợp lệ.