如何解决仅在触发了来自两个不同元素的两个事件时才如何运行函数?
我有两个媒体元素:
<audio id="aud"></audio>
<video id="vid"></video>
我已经将媒体网址附加到了这两个网址上。
然后我通过在监听器中依次进行audio.load()
和video.load()
和audio.play()
和video.play()
来加载和播放它们
audio.load();
video.load();
video.addEventListener("canplay",() => {
video.play();
});
audio.addEventListener("canplay",() => {
audio.play();
});
两者均开始加载,音频首先加载,视频加载大约需要1-2秒。
何时开始播放取决于每个媒体元素何时触发“ 可以播放”事件。 (加载至少两帧后触发)
我想做的是,仅当其中的两者都触发“ audio.play()
”事件时,才同时调用video.play()
和canplay
。我该如何实现?
请注意,我确实需要同时使用音频和视频元素,而且我正在尝试在开始时实现接近但并非完美的同步。
简而言之:我想要实现的是:
audio.load();
video.load();
// when video can "canplay" and when audio can "canplay" ONLY then
video.play();
audio.play();
解决方法
由canplay
事件解决并与Promise.all
结合以等待多个事件的承诺。
但是,它的复杂程度还取决于它的通用性。对于等待完全播放一个视频和一个音频的简单情况,我只使用一个承诺并在事件到达时对其进行计数。
请注意,要在检索文件的元素上捕获事件,在添加事件侦听器之前设置src
或href
属性是不安全的。
概念代码(未经测试)以添加侦听器,设置源并在两者都准备好时返回承诺:
const loadAV = (video,vidSrc,audio,audioSrc,timeout) {
let resolve,reject;
const p = new Promise( (r,j) => { resolve = r,reject = j};
let count = 0;
let timer;
const listenCanPlay = () => {
if( ++count == 2) {
resolve();
unListen();
}
};
const unListen = () => {
video.removeEventListener("canplay",listenCanPlay);
audio.removeEventListener("canplay",listenCanPlay);
if( timeout) {
clearTimeout(timer);
}
};
if( timeout) {
timer = setTimeout( ()=> {
if( count < 2) {
unListen();
reject( new Error(`loadAV timed out after ${timeout} msec`)
}
},timeout);
}
video.addEventListener("canplay",listenCanPlay);
audio.addEventListener("canplay",listenCanPlay);
video.src = vidSrc;
audio.src = audioSrc;
return p;
}
随后将被称为
loadAV( video,video_url,audio_url,15000)
.then(()=>{ video.play(); audio.play()})
.catch(err=> console.log(err));
,
使用全局标志:
let audCanPlay=false;
let vidCanPlay=false;
function audPlay() {
audCanPlay=true;
console.log("audCanPlay=true");
if(vidCanPlay) playBoth();
}
function vidPlay() {
vidCanPlay=true;
console.log("vidCanPlay=true");
if(audCanPlay) playBoth();
}
function playBoth() {
console.log("audio.play();");
console.log("video.play();");
}
/* commented for demonstration
audio.addEventListener("canplay",audPlay);
video.addEventListener("canplay",vidPlay);
audio.load();
video.load();
*/
<audio id="aud"></audio>
<button id="audBtn" onclick="audPlay()">Mimic Audio canplay</button>
<video id="vid"></video>
<button id="vidBtn" onclick="vidPlay()">Mimic Video canplay</button>
我认为最好在调用load方法之前添加事件侦听器。
我认为最好这样做,而不是等待一个完成/可以播放,然后再调用第二个=可以节省时间/更快。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。