Как запустить функцию только при запуске двух событий из двух разных элементов?

#javascript #synchronization #html5-video #html5-audio

#javascript #синхронизация #html5-видео #html5-аудио

Вопрос:

У меня есть два медиа-элемента:

 <audio id="aud"></audio>
<video id="vid"></video>
  

Я прикрепил к ним обоим URL-адреса мультимедиа.

Затем я загружаю и воспроизводю их, выполняя audio.load() и video.load() , а затем audio.play() и video.play() в прослушивателе

 audio.load();
video.load();
video.addEventListener("canplay", () => {
    video.play();     
});
audio.addEventListener("canplay", () => {
    audio.play();     
});
  

Оба начинают загружаться, сначала загружается аудио, а загрузка видео занимает около 1-2 секунд.

Когда они действительно начнут воспроизводиться, зависит от того, когда событие «canplay» запускается каждым медиа-элементом. (который запускается после загрузки, выполняется как минимум для пары кадров)

что я хочу сделать, так это вызывать audio.play() AND video.play() вместе ТОЛЬКО тогда, когда canplay для них обоих запускается событие «». Как я могу этого добиться?

обратите внимание, что мне нужно использовать как аудио, так и видеоэлемент, и я пытаюсь добиться близкой, но не идеальной синхронизации при запуске.

вкратце: чего я хочу добиться, так это:

 audio.load();
video.load();

// when video can "canplay" and when audio can "canplay" ONLY then

video.play();   
audio.play();
  

Комментарии:

1. Не загружайте их одно за другим. Запустите audio.load(); затем запустите video.load() при загрузке аудио. триггер воспроизводится для обоих после загрузки видео. : audio.load(); audio.addEventListener(«canplay», () => { video.load(); }); video.addEventListener(«canplay», () => { audio.play(); video.play(); });

2. Когда вы хотите дождаться завершения многих асинхронных действий, вы используете Promise.all : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference /…

3. @AntiqTech ваш ответ, похоже, намного меньше, чем у других, есть ли в нем возможный недостаток? или это только для МОЕГО варианта использования, который, кажется, подходит идеально?

4. Я просто перестроил ваш код. Единственный недостаток, о котором я могу думать, это то, что «audio.load();» может вызвать исключение или что событие «canplay» по какой-то причине никогда не запускается, что нарушает поток. Я могу добавить это в качестве ответа, если вы хотите проголосовать за него.

Ответ №1:

Используйте глобальные флаги:

 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>  

Я думаю, что лучше добавить прослушиватели событий перед вызовом методов загрузки.
Я думаю, что лучше сделать это таким образом, вместо того, чтобы ждать завершения одного / canplay и только затем вызывать второе = экономит время / быстрее.

Комментарии:

1. прослушиватели событий лучше использовать перед загрузкой asin? поскольку мы не должны очищать прослушиватель после запуска функции, я буду вызывать метод okay много раз во время воспроизведения..

2. Я не знаю, как работают аудио и видео. вероятно: let audio=document.getElementById("aud") и аналогично для видео, затем: addEventListener s, затем: load .

3. Что такое «метод okay»?

4. В функции playBoth вы можете добавить в конце: audCanPlay=false; vidCanPlay=false; , и: audio.removeEventListener("canplay", audPlay); video.removeEventListener("canplay", vidPlay); , но вам придется добавлять слушателей снова всякий раз, когда вы меняете источники. Я не знаю, canplay срабатывает ли более одного раза для каждого источника — если это не так = я не понимаю, зачем удалять слушателей — просто снимите флаги (установленные на false ).

5. См. canplay canplaythrough ). И HTMLMediaElement .

Ответ №2:

canplay На ум приходят обещания, разрешенные событиями и объединенные с Promise.all ожиданием нескольких событий.

Однако то, насколько сложной она должна быть, также зависит от того, насколько общей она должна быть. Для простого случая ожидания готовности к воспроизведению ровно одного видео и одного аудио я бы использовал только одно обещание и считал события по мере их поступления.

Обратите внимание, что для перехвата событий в элементах, которые извлекают файлы, небезопасно устанавливать src href атрибуты or перед добавлением прослушивателей событий.

Концептуальный код (непроверенный) для добавления слушателей, установки источников и возврата обещания, когда оба будут готовы:

 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));
  

Комментарии:

1. Привет, спасибо за замечательный ответ, хотя не могли бы вы, пожалуйста, проверить комментарий к моему вопросу от AntiqTech? В чем недостаток этого использования, оно кажется довольно маленьким для работы..

2. @shriyanskapoor хорошо, что все просто. Если загрузка ресурсов последовательно приемлема с точки зрения производительности, то загрузка их таким образом потребует меньше кода. Следует включить обработку условий ошибки, и разрешение воспроизведения другой видео- и звуковой дорожки после завершения первой пары снова начнет усложнять ситуацию. Всего наилучшего в ваших начинаниях.