SetTimeout dijalankan lebih cepat dari yang diharapkan

Saya sedang belajar javascript:

Saat ini saya mencoba membuat permainan di mana hewan akan muncul setiap waktu secara acak, antara satu dan dua detik, lalu kita dapat mengekliknya dan membuatnya menghilang.

Saya menghadapi kesulitan karena saya telah menambahkan SetTimeout untuk menunggu hingga animasi lompat berakhir, untuk menghapus kelas CSS-nya untuk menghapus hewan tersebut.

Namun hewan-hewan tersebut hanya muncul pertama kali, kemudian pelaksanaan fungsi lompat berjalan cepat sehingga hewan-hewan tersebut tidak muncul.

Saya sudah mencoba men-debug programnya, pertama kita melihat hewan di div yang sama yang telah dihitung secara acak:

masukkan deskripsi gambar di sini

Pada langkah berikutnya, kita melihat bahwa hewan tersebut muncul di lubang kedua, dan debugger masih mencatat bahwa lubang yang digunakan adalah lubang kelima:

masukkan deskripsi gambar di sini

Ini adalah langkah berikutnya ketika kita melihat div 2 telah digunakan:

masukkan deskripsi gambar di sini

Dan lagi-lagi debugger masih mengatakan bahwa div 2 telah digunakan ketika hewan tersebut muncul dari 1:

masukkan deskripsi gambar di sini

Selain itu jika saya mencoba menjalankan program dengan debugger, hewan hanya muncul pertama kali dan kemudian selalu bersembunyi. Ditambah lagi di konsol kita melihat banyak console.log dengan waktu dan lubang setiap detiknya sekaligus.

masukkan deskripsi gambar di sini

Ini kode saat ini:

indeks.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="/idstyle.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>

Saya kira itu adalah fungsi jump() yang berperilaku tidak terduga, namun bagaimana kita bisa menelurkan hewan tersebut, menunggu transisi, dan menyembunyikannya, lalu memunculkan yang baru?.

gaya.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;
}

Sunting:

Terima kasih @Scott Marcus atas bantuan Anda, saya menghargainya.

Saya sudah mencoba kode berikut, saya hanya akan memasukkan fungsi lompat:

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

Saya telah menemukan bahwa jika kita menggulir dengan roda mouse, hewan-hewan akan bertelur, di Opera:

masukkan deskripsi gambar di sini

Namun kami belum memasang evenetListener pada skrip.

Selain itu di Mozilla mereka tidak muncul sama sekali:

masukkan deskripsi gambar di sini

Bahkan jika kita melihat di konsol bagaimana randomTime dan randomHole dihitung dan ditampilkan.

Bagaimana kita bisa membuat hewan-hewan itu bertelur?

Saya pikir penyebab mengapa mereka tidak muncul adalah karena pengatur waktu dijalankan terlalu cepat, meskipun kita menyimpan pengatur waktu terakhir, pengatur waktu terakhir dan menghapusnya jika belum selesai.

Terima kasih atas bantuan Anda!!


person Enoy    schedule 08.04.2018    source sumber


Jawaban (1)


Karena fungsi jump Anda berisi setTimeout dan fungsi panggilan balik pengatur waktu membuat panggilan rekursif ke jump, Anda memiliki skenario di mana panggilan kedua ke jump dapat terjadi sebelum pengatur waktu pertama berjalan atau selesai. Hal ini dapat menyebabkan beberapa fungsi panggilan balik pengatur waktu menjadi "ditumpuk" dalam antrean peristiwa dan dijalankan, satu demi satu. Ini mungkin perilaku yang Anda lihat.

Anda perlu memastikan bahwa panggilan tambahan ke jump tidak memulai penghitung waktu tambahan, yang dapat menyebabkan efek yang Anda jelaskan.

Anda mencapai hal ini dengan memastikan bahwa hanya satu pengatur waktu yang dapat berjalan pada satu waktu dan hal ini dicapai dengan menangkap pengidentifikasi unik pengatur waktu dan memastikan untuk membatalkan pengatur waktu terakhir sebelum memulai pengatur waktu yang baru.

var timer = null; // This will hold the most recent timer's id

function jump() {
    clearTimeout(timer); // Cancel any previous timer

    let time = randomTime(1000, 2000);
    let hole = randomHole(holes);
    console.log(time, hole);
    hole.classList.add('up');

    // Capture a reference to the most recent timer
    timer = setTimeout(() => {
        hole.classList.remove('up');
        debugger;
        jump();
    }, time);
}
person Scott Marcus    schedule 08.04.2018
comment
Terima kasih @Scott Marcus atas bantuan baik Anda. Saya telah mencoba menyimpan pengatur waktu saat ini dalam sebuah variabel dan kemudian crearTimeout sebagai instruksi lompatan pertama, namun pengatur waktu tersebut tidak muncul sama sekali di Mozilla, dan di Opera mereka hanya muncul pada eksekusi pertama, kemudian setelah yang pertama menghilang, yang lain tidak muncul ke atas. - person Enoy; 08.04.2018
comment
@Enoy Sejujurnya, saya belum memeriksa semua kode Anda. Kemungkinan besar Anda masih mengalami masalah dengan aspek lain dari kode tersebut, namun apa yang saya bagikan di sini membahas tentang percepatan penghitung waktu yang Anda tanyakan. - person Scott Marcus; 08.04.2018