我正在编写 Javascript 来播放一系列重复的动画,这些动画转到浏览器中播放的歌曲的音符。这是我目前有效的代码:
//Determine the timing for each note played
var expTimes = [0, 215, 323, 645, 860, 968, 1290...]
var strumTimeout;
//Loop through the array and strum at each listed timeout through the duration of the audio
function StrumPattern(strumArray){
//Toggles the CSS transforms to make the strum animation happen
function strum(){
if (strumHand.style.transform == "rotate(50deg)"){
strumHand.style.transform = "rotate(0deg)";
}else{
strumHand.style.transform = "rotate(50deg)";
}
}
//Sets the timeout for each strum animation to play in a sequence
strumArray.forEach(delay => {
strumTimeout = setTimeout(() => {
strum();
console.log("strum");
}, delay);
});
}
但是,我希望能够在用户关闭音乐时清除所有这些超时。通过在 strum() 周围添加 if 语句,我能够使弹奏动画停止;函数,但它不会阻止 forEach 循环在数组中运行,如果我在数组完成之前再次播放动画,它会变得非常紧张,因为它同时运行两个 forEach 循环。
我尝试使用下面的这个函数来定位我认为会在 forEach 循环中标记为 strumTimeout 的所有 setTimeout。但这不起作用,因为它摆脱了页面上的所有 setTimeout 函数,当我有其他 setTimeout 函数需要运行以在不同点停止其他动画时。
//Clears
function clearStrum(){
var id = strumTimeout;
while (id--) {
console.log('removing timeout');
window.clearTimeout(id); // will do nothing if no timeout with id is present
}
}
此外,每次激活它时,console.log 都会打印出越来越多的“删除超时”字符串
我也尝试过使用常规的 for 循环和中断,但它要么不起作用,要么说“跳转目标不能跨越函数边界”,这取决于我把它放在哪里。
如果有一种方法可以标记由 forEach 循环创建的 setTimeouts 并以某种方式清除或删除它们,这就是我正在寻找的。但是,如果有更好的方法让动画在可变超时时间或间隔时间的序列中播放,我也很想听听。
Array#map
从数组中的循环中获取所有超时ID,以便稍后清除。
// outside the function
let timeouts;
// inside the function, replace strumArray.forEach with the following:
timeouts = strumArray.map(delay => setTimeout(() => {
strum();
console.log("strum");
}, delay));
// cancel all those timeouts later:
timeouts?.forEach(id => clearTimeout(id));