Когда я приостанавливаю звук и устанавливаю для него currentTime, происходит что-то странное. когда я нажимаю кнопку, которая управляет состоянием звука .paused, кажется, что она снова автоматически нажимается, предотвращая воспроизведение звука. Почему?
Кроме того, если я снова установлю currentTime, он решит перестать нажимать кнопку воспроизведения дважды. это происходит каждый раз, когда я устанавливаю currentTime. это можно продемонстрировать с помощью этого кода. (замедленный звук происходит только потому, что пример слишком короткий).
<!doctype html><html><body>
<button id = "play" disabled>play</button>
<button id = "idk">load audio</button>
<script>
var clicks = 0; console.clear();
idk = document.getElementById("idk");
idk.addEventListener("click", async ()=>{
aud = new Audio("https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3")
aud.addEventListener('canplaythrough', init);
}, {once: true});
function init(){
/**/aud.playbackRate = 0.25;//only to lengthen the audio to give you time.
playButton = document.getElementById("play");
playButton.disabled = false;
idk.innerText = "pause and set time to 1";
playButton.addEventListener("click", e=>{
if (aud.paused){
aud.play();
playButton.innerText = "pause";
}else{
aud.pause();
playButton.innerText = "play";
}
//Nothing different between duplicate click events, logging it takes up space
console.info(clicks++, aud.paused, /*e*/);//clicks++ to tell apart logs.
});
idk.addEventListener("click", e=>{
console.info("Rightmost element clicked");
if (!aud.paused){ aud.pause(); playButton.innerText = "play"; }
aud.currentTime = 1;
});
}
</script>
</body></html>
См. живой пример (убрано ведение журнала событий из-за загрязнения консоли)
просто нажмите load audio, затем нажмите play, как только разрешите, и, наконец, нажмите pause and set time to 1.
после этого событие щелчка будет запускаться дважды при каждом фактическом щелчке (как видно из журнала), предотвращая воспроизведение звука. единственный способ исправить это — снова нажать pause and set time to 1 и попытаться нажать play. У вас все получится, но если вы еще раз нажмете правую кнопку, вы снова столкнетесь с этой проблемой.
Я также заметил, что двойной щелчок при незначительном изменении превращается в четырехкратный щелчок, что по-прежнему вызывает проблему, поскольку 4 щелчка — это четное число.
<!doctype html><html><body>
<button id = "play">play</button>
Control+Click to pause the audio and change it's currentTime value
<script>
var clicks = 0; console.clear();
playButton = document.getElementById("play");
playButton.addEventListener("click", async ()=>{
/**/window.aud = new Audio("https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3");
aud.addEventListener('canplaythrough', ()=>{
playButton.style.color = "#080";
/**/aud.playbackRate = 0.25;//only to lengthen the audio to give you time.
playButton.addEventListener("click", e=>{
if (e.ctrlKey){
if (!aud.paused){ aud.pause(); playButton.innerText = "play"; }
aud.currentTime = 1;
return;
}
if (aud.paused){
aud.play();
playButton.innerText = "pause";
}else{
aud.pause();
playButton.innerText = "play";
}
//Nothing different between duplicate click events, logging it takes up space
console.info(clicks++, aud.paused, /*e*/);//clicks++ to tell apart logs.
});
});
}, {once: true});
</script>
</body></html>
См. живой пример (убрано ведение журнала событий из-за загрязнения консоли)
чтобы использовать второй пример, используйте CTRL+кликните по кнопке pause and set time to 1.
в обоих примерах запуск aud.play(); в консоли, кажется, работает, но по-прежнему не позволяет кнопке воспроизведения/паузы действовать и дважды щелкает по ней. Установка aud.currentTime в консоли (после того, как она была установлена четное количество раз) не имеет никакого эффекта, как и установка кода aud.currentTime дважды подряд. Пользователь должен щелкнуть по нему, а затем щелкнуть по нему еще раз.
Это происходит в бета-версии Chrome 127.0.6533.94 в ChromeOS, а также в Chrome 127.0.6533.85 и Firefox 129.0 на Android 14. Я вообще не могу заставить его работать на iOS, не входящей в ЕС.
Заранее извините, если этого тестирования недостаточно, или я допустил действительно очевидную ошибку.
Это упрощенное определение ошибки, возникающей в более крупной кодовой базе (без «базы», но все же значительно большей, чем эти коды). Некоторые из предложенных изменений могут быть несовместимы с моим случаем, поэтому мне бы очень хотелось (и предпочитаю, даже без исправлений, но был бы рад и исправлению) понять проще говоря, что происходит на самом деле и почему. Если исправление включено, по возможности измените немного. все, что я знаю, это то, что когда currentTime изменяется, код не работает должным образом, а в противном случае он приостанавливается и работает отлично. Никакие посторонние события не прослушиваются, как это обнаружено в DevTools, асинхронность остается там случайно, она является частью реальной кодовой базы.
В центре внимания находится код, включающий «idk», а другой — это просто код, с которым я столкнулся, пытаясь еще больше упростить код для stackoverflow, пока не нашел его, щелкнув четыре раза.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Чтобы решить вашу проблему, вам следует учитывать несколько моментов:
Дублирование прослушивателя событий: каждый раз, когда вы нажимаете кнопку play, добавляется новый прослушиватель событий. Это может привести к запуску нескольких прослушивателей событий, что приведет к поведению двойного щелчка. Чтобы это исправить, убедитесь, что прослушиватель событий добавлен только один раз.
Различия в браузерах: разные браузеры, например, в Google Chrome, обрабатывают свойство currentTime по-разному, как сказано в этом вопросе StackOverflow и в MDN Docs: BaseAudioContext: свойство currentTime.
В данном случае ваша проблема заключается в том, что вы несколько раз запускали событие click на кнопке play из-за дублирования событий. Вот код:
<!doctype html>
<html>
<body>
<button id = "play" disabled>play</button>
<button id = "idk">load audio</button>
<script>
var clicks = 0;
console.clear();
idk = document.getElementById("idk");
idk.addEventListener("click", async () => {
aud = new Audio("https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3");
aud.addEventListener('canplaythrough', init, { once: true });
}, { once: true });
function init() {
aud.playbackRate = 0.25; // only to lengthen the audio to give you time.
playButton = document.getElementById("play");
playButton.disabled = false;
idk.innerText = "pause and set time to 1";
playButton.addEventListener("click", togglePlayPause, { once: true });
idk.addEventListener("click", setTimeToOne, { once: true });
}
function togglePlayPause() {
if (aud.paused) {
aud.play();
playButton.innerText = "pause";
} else {
aud.pause();
playButton.innerText = "play";
}
console.info(clicks++, aud.paused);
playButton.addEventListener("click", togglePlayPause, { once: true });
}
function setTimeToOne() {
console.info("Rightmost element clicked");
if (!aud.paused) {
aud.pause();
playButton.innerText = "play";
}
aud.currentTime = 1;
idk.addEventListener("click", setTimeToOne, { once: true });
}
</script>
</body>
</html>
Это гарантирует, что функция togglePlayPause вызывается только один раз за клик, предотвращая проблему с несколькими прослушивателями событий.
Сейчас у меня нет компьютера, но я хотел бы отметить, что DevTools не отображал более одного прослушивателя событий на каждой кнопке одновременно (то же самое касается версии только для воспроизведения).
Буду прост: ваш ответ, по крайней мере, по мере наименьших крайних изменений и позволил мне найти ответ самому, не прибегая к {разу:правде} исступлению. Я не мог мысленно придать какое-либо значение какому-либо некодовому тексту, так как он кажется неуместным, но ваш код был прекрасен, однако я этически обязан отдать награду Роко Бульяну, даже несмотря на его серьезные изменения. Он категорически заявил: «Избегайте создания событий и функций внутри других функций событий», что я пропустил, потому что слишком много внимания уделял коду, и его было трудно понять. Желаю тебе удачи в будущей охоте за головами
Вот гораздо более чистый подход:
"click"). Один из способов — использовать {once: true} в качестве параметров события (третий аргумент), но это усложняет код, и его трудно рассуждать и отлаживать.const, let), чтобы не загрязнять глобальную область видимости.const aud = new Audio(); в свои переменные. Вы добавите .source позжеload() (с конкретной паузой + время), toggle() для переключения воспроизведения/паузы и updateUI() единственная задача которых - заботиться о пользовательском интерфейсе в зависимости от aud.paused и звука. .readyState состояния"canplaythrough", "play" и "pause" для вызова changeUIload() и toggle().const source = "https://upload.wikimedia.org/wikipedia/en/3/39/Metallica_-_Enter_Sandman.ogg";
const elLoad = document.querySelector("#load");
const elPlay = document.querySelector("#play");
const aud = new Audio(); // Set Audio constructor right away
// FUNCTIONS
const load = () => {
aud.pause();
if (aud.src !== source) aud.src = source;
else aud.currentTime = 5;
};
const toggle = () => {
aud[aud.paused ? "play" : "pause"]();
};
const updateUI = () => {
elPlay.disabled = !aud.readyState;
elPlay.textContent = aud.paused ? "Play" : "Pause";
elLoad.textContent = aud.readyState ? "Pause and set time to 5s" : "Load audio";
};
// EVENTS
aud.addEventListener("canplaythrough", updateUI);
aud.addEventListener("pause", updateUI);
aud.addEventListener("play", updateUI);
elLoad.addEventListener("click", load);
elPlay.addEventListener("click", toggle);
// INIT
updateUI();<button id = "play" disabled></button>
<button id = "load"></button>Слишком сложный и экстремальный вариант изменений, но я должен рассказать вам об этом с первого пункта. Первая пуля была единственной пулей, которая влияла на то, сделала ли она то, что ожидалось, или нет. Тем не менее, я ломаю голову над тем, почему Chromium и Firefox ненавидят прослушиватели событий вложенных встроенных функций.
Проблема в том, что Chromium и Firefox ненавидят, когда я помещаю прослушиватель событий «щелчка» кнопки воспроизведения внутри init (функция прослушивателя, а не вызов addEventListener). ответ предполагает размещение и определение этой функции где-нибудь за пределами функции прослушивателя событий Audio.oncanplaythrough, например:
<!doctype html><html><body>
<button id = "play" disabled>play</button>
<button id = "idk">load audio</button>
<script>
var clicks = 0; console.clear();
idk = document.getElementById("idk");
idk.addEventListener("click", async ()=>{
aud = new Audio("https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3")
aud.addEventListener('canplaythrough', init);
}, {once: true});
function playButtonClick(e){
if (aud.paused){
aud.play();
playButton.innerText = "pause";
}else{
aud.pause();
playButton.innerText = "play";
}
//Nothing different between duplicate click events, logging it takes up space
console.info(clicks++, aud.paused, /*e*/);//clicks++ to tell apart logs.
}
function init(){
/**/aud.playbackRate = 0.25;//only to lengthen the audio to give you time.
playButton = document.getElementById("play");
playButton.disabled = false;
idk.innerText = "pause and set time to 1";
playButton.addEventListener("click", playButtonClick);
idk.addEventListener("click", e=>{
console.info("Rightmost element clicked");
if (!aud.paused){ aud.pause(); playButton.innerText = "play"; }
aud.currentTime = 1;
});
}
</script>
</body></html>
Но теперь Chrome просто возится со мной, и теперь мне приходится делать это с каждым вложенным прослушивателем кликов, с которым я когда-либо сталкивался.
У вас есть
playButton.addEventListener("click"внутриplayButton.addEventListener("click"— то же самое касаетсяidk.addEventListener("click"иaud.addEventListener('canplaythrough', init);. Избегайте этого. Создайте другую логику или используйте{once: true}для внутренних кликов. Кроме того,asyncне нужен.