仅当来自两个不同元素的两个事件被触发时,如何 运行 一个函数?
How to run a function only when two events from two different elements have fired?
我有两个媒体元素:
<audio id="aud"></audio>
<video id="vid"></video>
我已将媒体 URL 附加到它们。
然后我通过执行 audio.load()
和 video.load()
然后在 listener
中执行 audio.play()
和 video.play()
来加载和播放它们
audio.load();
video.load();
video.addEventListener("canplay", () => {
video.play();
});
audio.addEventListener("canplay", () => {
audio.play();
});
两者都开始加载,首先加载音频,加载视频大约需要 1-2 秒。
它们实际开始播放的时间取决于每个媒体元素何时触发“canplay”事件。 (在加载至少几帧后触发)
我想做的是,只有当 both 触发了“canplay
”事件时,才同时调用 audio.play()
和 video.play()
.我怎样才能做到这一点?
请注意,我确实需要同时使用音频和视频元素,并且我试图在开始时实现接近但不完美的同步。
简而言之:我想要实现的是:
audio.load();
video.load();
// when video can "canplay" and when audio can "canplay" ONLY then
video.play();
audio.play();
由 canplay
事件解决并结合 Promise.all
等待多个事件的承诺浮现在脑海中。
但是,它需要多复杂也取决于它的通用性。对于等待正好 one 视频和 one 音频准备播放的简单情况,我只会使用一个承诺并将事件计数为他们到了。
请注意,要在检索文件的元素上捕获事件,在添加事件侦听器之前设置 src
或 href
属性是不安全的。
添加侦听器、设置源和return承诺的概念代码(未经测试):
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, 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>
我认为最好在调用加载方法之前添加事件侦听器。
我认为这样做更好,而不是等待一个 finish/canplay 然后才调用第二个 = 保存 time/faster.
我有两个媒体元素:
<audio id="aud"></audio>
<video id="vid"></video>
我已将媒体 URL 附加到它们。
然后我通过执行 audio.load()
和 video.load()
然后在 listener
audio.play()
和 video.play()
来加载和播放它们
audio.load();
video.load();
video.addEventListener("canplay", () => {
video.play();
});
audio.addEventListener("canplay", () => {
audio.play();
});
两者都开始加载,首先加载音频,加载视频大约需要 1-2 秒。
它们实际开始播放的时间取决于每个媒体元素何时触发“canplay”事件。 (在加载至少几帧后触发)
我想做的是,只有当 both 触发了“canplay
”事件时,才同时调用 audio.play()
和 video.play()
.我怎样才能做到这一点?
请注意,我确实需要同时使用音频和视频元素,并且我试图在开始时实现接近但不完美的同步。
简而言之:我想要实现的是:
audio.load();
video.load();
// when video can "canplay" and when audio can "canplay" ONLY then
video.play();
audio.play();
由 canplay
事件解决并结合 Promise.all
等待多个事件的承诺浮现在脑海中。
但是,它需要多复杂也取决于它的通用性。对于等待正好 one 视频和 one 音频准备播放的简单情况,我只会使用一个承诺并将事件计数为他们到了。
请注意,要在检索文件的元素上捕获事件,在添加事件侦听器之前设置 src
或 href
属性是不安全的。
添加侦听器、设置源和return承诺的概念代码(未经测试):
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, 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>
我认为最好在调用加载方法之前添加事件侦听器。
我认为这样做更好,而不是等待一个 finish/canplay 然后才调用第二个 = 保存 time/faster.