SetTimeout执行速度快于预期

时间:2018-04-08 16:52:40

标签: javascript html css animation timer

我正在学习javascript:

我正在尝试做一个动物应该在每个随机时间产生一到两秒之间的游戏,然后我们可以点击它们并让它们消失。

我遇到了一个困难,因为我添加了一个SetTimeout来等待跳转动画结束,删除它的CSS类以删除动物。

然而动物只是第一次显示,然后,跳跃功能的执行很快就会出现,所以动物不会出现。

我试过调试程序,首先我们看到同一个div上的动物是随机计算的:

enter image description here

在下一步中,我们看到动物出现在第二个洞,并且调试器仍在记录已使用的孔是第五个:

enter image description here

当我们看到div 2被使用时,它是下一步:

enter image description here

再一次,调试器仍然说当动物从1产生时使用了div 2:

enter image description here

此外,如果我尝试用调试器执行程序,动物只会显示第一次,然后它们总是隐藏。另外在控制台中我们每隔一秒就会看到很多带有时间和漏洞的console.log。

enter image description here

以下是当前代码:

的index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Whack A Mole!</title>
    <link href='https://fonts.googleapis.com/css?family=Amatic+SC:400,700' rel='stylesheet' type='text/css'>
    <link rel="stylesheet" href="style.css">
</head>
<body>

<h1>Whack-a-mole! <span class="score">0</span></h1>
<button onClick="startGame()">Start!</button>

<div class="game">
    <div class="hole hole1">
        <div class="mole"></div>
    </div>
    <div class="hole hole2">
        <div class="mole"></div>
    </div>
    <div class="hole hole3">
        <div class="mole"></div>
    </div>
    <div class="hole hole4">
        <div class="mole"></div>
    </div>
    <div class="hole hole5">
        <div class="mole"></div>
    </div>
    <div class="hole hole6">
        <div class="mole"></div>
    </div>
</div>

<script>
    const holes = document.querySelectorAll('.hole');
    const scoreBoard = document.querySelector('.score');
    const moles = document.querySelectorAll('.mole');

    let lastHole;

    function randomTime(min, max) {
        const time = Math.round(Math.random() * (max - min) + min);
        console.log(time);
    }

    function randomHole(holes) {
        const index = Math.floor(Math.random() * holes.length);
        const hole = holes[index];
        if (hole === lastHole) {
            console.log('We calculate a new hole!');
            return randomHole(holes);
        }
        lastHole = hole;
        return hole;
    }

    function jump() {
        let time = randomTime(1000, 2000);
        let hole = randomHole(holes);
        console.log(time, hole);
        hole.classList.add('up');
        setTimeout(() => {
            hole.classList.remove('up');
            debugger;
            jump();
        }, time);
    }

    jump();

</script>
</body>
</html>

我认为跳跃()函数是一个出乎意料的行为但是,我们怎么能产生动物,等待过渡,隐藏它,然后再出现一个新的?。

的style.css

html {
  box-sizing: border-box;
  font-size: 10px;
  background: #ffc600;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  padding: 0;
  margin:0;
  font-family: 'Amatic SC', cursive;
}

h1 {
  text-align: center;
  font-size: 10rem;
  line-height:1;
  margin-bottom: 0;
}

.score {
  background:rgba(255,255,255,0.2);
  padding:0 3rem;
  line-height:1;
  border-radius:1rem;
}

.game {
  width:600px;
  height:400px;
  display:flex;
  flex-wrap:wrap;
  margin:0 auto;
}

.hole {
  flex: 1 0 33.33%;
  overflow: hidden;
  position: relative;
}

.hole:after {
  display: block;
  background: url(dirt.svg) bottom center no-repeat;
  background-size:contain;
  content:'';
  width: 100%;
  height:70px;
  position: absolute;
  z-index: 2;
  bottom:-30px;
}

.mole {
  background:url('mole.svg') bottom center no-repeat;
  background-size:60%;
  position: absolute;
  top: 100%;
  width: 100%;
  height: 100%;
  transition:all 0.4s;
}

.hole.up .mole {
  top:0;
}

编辑:

谢谢@Scott Marcus的帮助,我很感激。

我已经尝试了以下代码,我只是将跳转功能:

<script>
    const holes = document.querySelectorAll('.hole');
    const scoreBoard = document.querySelector('.score');
    const moles = document.querySelectorAll('.mole');

    let lastHole;
    let timer = null;

    function randomTime(min, max) {
        const time = Math.round(Math.random() * (max - min) + min);
        console.log(time);
    }

    function randomHole(holes) {
        const index = Math.floor(Math.random() * holes.length);
        const hole = holes[index];
        if (hole === lastHole) {
            console.log('We calculate a new hole!');
            return randomHole(holes);
        }
        lastHole = hole;
        return hole;
    }

    function jump() {
        clearTimeout(timer);
        let time = randomTime(1000, 2000);
        let hole = randomHole(holes);
        console.log(time, hole);
        hole.classList.add('up');
        timer = setTimeout(() => {
            hole.classList.remove('up');
            debugger;
            jump();
        }, time);
    }

    jump();

</script>

我发现,如果我们用鼠标滚轮滚动,动物会在Opera中产生:

enter image description here

但是我们没有在脚本上放置evenetListener。

此外,在Mozilla中,他们根本没有出现:

enter image description here

即使我们在控制台中看到如何计算和显示randomTime和randomHole。

我们怎样才能让动物产卵?

我认为他们没有显示的原因是因为定时器执行得太快,即使我们保存最后一个,最后一个计时器并清除它还没有完成。

感谢您的帮助!!

1 个答案:

答案 0 :(得分:1)

由于您的jump函数包含setTimeout并且计时器的回调函数对jump进行递归调用,因此您有一个第二次调用{{1}的方案可以在第一个计时器运行或完成之前发生。这可能导致多个计时器回调函数变为“堆叠”#34;在事件队列中运行,一个紧接着另一个。这可能是您所看到的行为。

您需要确保对jump的其他来电不会启动其他定时器,这可能会导致您所描述的效果。

通过确保一次只能运行一个计时器并通过捕获计时器的唯一标识符并确保在开始新计时器之前取消最后一个计时器来实现此目的。

jump