如何使循环延迟随每个周期而变化的时间量?

How can I make a loop be delayed by an amount of time that changes with every cycle?

提问人:ThisNameTagPasses 提问时间:7/19/2023 最后编辑:ThisNameTagPasses 更新时间:7/19/2023 访问量:59

问:

我正在尝试在 javascript 中制作一个游戏循环,其中每 x 次发生一次事件,并且每个循环的时间会变短。

这是我尝试使用的代码:


const begin = document.getElementById("startbtn")

begin.onclick = start;

//Game loop

function start() {

    console.log("test");

    let i = 1000;

    while (i>0) {
        loop(i);
        i = i - 100;
        }

    function loop(i){
        setTimeout(function(){
            console.log("adsafsd");
        }, 5 * i);
    }

}

但它只是以相同的间隔重复,并在 5 次循环后大约 10 秒内完成。 我想象循环函数中的 setTimeout 会变得更短,因为它需要 i 变量的 5 倍,每个循环减去 100。

JavaScript HTML 循环 延迟

评论

0赞 Christian Vincenzo Traina 7/19/2023
在您的示例中,您正在设置超时,但您没有等待它过去后再开始新的超时。

答:

4赞 Alexander Nenashev 7/19/2023 #1

您可以使用并包装成一个 promise 来使代码更易于管理:async/awaitsetTimeout

let game;

const timeout = (delay = 0) => new Promise(resolve => setTimeout(resolve, delay));

const restart = () => stop() + start(game = {running: true});

const stop = () => game && delete game.running;

async function start(game) {

    console.log('game started');
    
    let delay = 500; // start delay

    while (delay > 0) { 
       await timeout(delay); 
       if(!game.running){
         break;
       }
       console.log(`delay ${delay}`);
       delay -= 50; // your interval decrement
    }

}
button{
  background: lightgray;
  border:none;
  border-radius:50%;
  padding: 10px 20px;
  cursor:pointer;
}
button:hover{
  background:#ddd;
  box-shadow: 0 0 10px rgba(0,0,0,.2);
}
<button onclick="restart()">Start</button> <button onclick="stop()">Stop</button>

评论

0赞 Roko C. Buljan 7/19/2023
有时会很好,不是吗?另外 - 最好改用 addEventListener。clearTimeoutbegin.onclick
0赞 Alexander Nenashev 7/19/2023
@RokoC.Buljan 添加了
0赞 Alexander Nenashev 7/19/2023
@RokoC.Buljan 没有必要清除超时,只需打破while
1赞 Ryan McDonough 7/19/2023 #2

如果您不想像其他(非常好的)答案那样切换到异步:

当前代码几乎同时创建所有超时,每个超时的延迟都会随着每次迭代而减少 100 毫秒。但是,setTimeout 是异步工作的,因此它不会等待上一个超时完成再设置下一个超时,这意味着所有超时几乎同时设置。因此,它们几乎一起结束,只是彼此之间有轻微的延迟。

您应该在上一个超时完成后设置下一个超时。您可以通过在循环函数中使用递归来实现此目的:

const begin = document.getElementById("startbtn");

begin.onclick = start;

function start() {
    console.log("test");
    loop(1000);
}

function loop(i) {
    setTimeout(function() {
        console.log("Looping...");
        if (i > 100) {
            loop(i - 100);
        }
    }, 5 * i);
}
1赞 Wanderson Santos 7/19/2023 #3

以您的示例为例:

const begin = document.getElementById("startbtn");

begin.onclick = start;

// Game loop
function start() {
    console.log("test");

    let delay = 1000;

    function loop() {
        setTimeout(function () {
            console.log("adsafsd");
            delay -= 100;
            if (delay > 0) {
                loop();
            }
        }, delay);
    }

    loop();
}

但我认为这个问题的最佳模型是:

const begin = document.getElementById("startbtn");

begin.onclick = start;

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Game loop
async function start() {
    console.log('game started');

    for (let delay = 1000; delay > 0; delay -= 100) {
        await sleep(delay);
        console.log("adsafsd");
    }
}