简体   繁体   中英

Vanila JavaScript problem with setInterval and clearInterval

I am trying to build a simple multiplication game using pure Javascript. When I click start button it calls a function timeCalc(). The timeCalc function declares a variable name fullTime with the value of 7 and sets interval and after every second fullTime is decreasing by 1. when it decreases to 1 it sets the fullTime value to 7.

If I click on the start button many times the fullTime decreses so fast and in a disorder way even If I have done clearInterval() at the begining. I want to decrese the fullTime from 7 in a normal way even if I click it many times. what happens behind the scene?

Here is my code snippet. Thank you.

 const timeContainer = document.querySelector('.math__time'); const startBtn = document.querySelector('.math__start'); function timeCalc() { clearInterval(timeLeft); let fullTime = 7; timeContainer.textContent = fullTime; var timeLeft = setInterval(function() { fullTime--; timeContainer.textContent = fullTime; if (fullTime === 1) { fullTime = 7; } },1000); } startBtn.addEventListener('click', timeCalc); 
 *, *:before, *:after { margin: 0; padding: 0; box-sizing: border-box; } .math { background: gray; font-family: verdana, sans-serif; } .math__calc { position: absolute; left: 50%; top: 50%; transform: translateY(-50%) translateX(-50%); } .math__num { margin: 15px; color: #fff; font-size: 30px; padding-left: 100px; } .math__num--wrapper { position: relative; } .math__time { padding: 10px; background: black; color: #fff; position: absolute; right: 20px; top: 20px; border: #fff 2px solid; } .math__start { position: absolute; left: 20px; top: 20px; border: 2px solid #fff; background: #333; color: #fff; padding: 10px; } .math__multiply--symbol { position: absolute; bottom: -10px; left: 10px; font-size: 30px; } 
 <!DOCTYPE html> <html> <head> <title>Math</title> <!-- default css --> <link rel="stylesheet" type="text/css" href="css/main.css"> </head> <body class="math"> <div class="math__time">0</div> <button class="math__start">Start</button> <div class="math__calc"> <div class="math__num--wrapper"> <div class="math__num math__num--one">88</div> <span class="math__multiply--symbol">*</span> <div class="math__num math__num--two">22</div> </div> <form class="math__ans"> <input type="text" name="answer" class="math__ans--user"> </form> </div> </body> </html> 

You need to declare timeLeft in global scope and change it inside function

 const timeContainer = document.querySelector('.math__time'); const startBtn = document.querySelector('.math__start'); let timeLeft; let fullTime; function timeCalc() { clearInterval(timeLeft); fullTime = 7; timeContainer.textContent = fullTime; timeLeft = setInterval(function() { fullTime--; timeContainer.textContent = fullTime; if (fullTime === 1) { fullTime = 8 } },1000); } startBtn.addEventListener('click', timeCalc); 
 *, *:before, *:after { margin: 0; padding: 0; box-sizing: border-box; } .math { background: gray; font-family: verdana, sans-serif; } .math__calc { position: absolute; left: 50%; top: 50%; transform: translateY(-50%) translateX(-50%); } .math__num { margin: 15px; color: #fff; font-size: 30px; padding-left: 100px; } .math__num--wrapper { position: relative; } .math__time { padding: 10px; background: black; color: #fff; position: absolute; right: 20px; top: 20px; border: #fff 2px solid; } .math__start { position: absolute; left: 20px; top: 20px; border: 2px solid #fff; background: #333; color: #fff; padding: 10px; } .math__multiply--symbol { position: absolute; bottom: -10px; left: 10px; font-size: 30px; } 
 <!DOCTYPE html> <html> <head> <title>Math</title> <!-- default css --> <link rel="stylesheet" type="text/css" href="css/main.css"> </head> <body class="math"> <div class="math__time">0</div> <button class="math__start">Start</button> <div class="math__calc"> <div class="math__num--wrapper"> <div class="math__num math__num--one">88</div> <span class="math__multiply--symbol">*</span> <div class="math__num math__num--two">22</div> </div> <form class="math__ans"> <input type="text" name="answer" class="math__ans--user"> </form> </div> </body> </html> 

Maheer is right, only addition would be to not pollute your global space. Create a closure to hold these variables. I updated the function to return a function.

The problem

Your clearInterval(timeLeft) is actually not clearing anything. The timeLeft is undefined at the moment of clearing.

The Solution

Moving your timeleft is in a higher scope. You can either: - Put it in the global namespace (Not recommended) - Create a scope around the timeCalc function.

I implemented the second solution below. I first changed the timeCalc() . Now the timeCalc() produces a function. This function can be used as the callback in for the .addEventListener() .

Then calling that function in the .addEventListener() will return a timer function with variables enclosed in a closure. I also changed the fulltime in the function to 8 to show 7 seconds after the countdown reached 1.

 const timeContainer = document.querySelector('.math__time'); const startBtn = document.querySelector('.math__start'); function timeCalc() { let timeLeft = null; let fullTime = 7; return function() { clearInterval(timeLeft); fullTime = 7; timeContainer.textContent = fullTime; timeLeft = setInterval(function() { fullTime--; timeContainer.textContent = fullTime; if (fullTime === 1) { fullTime = 8; } },1000); } } startBtn.addEventListener('click', timeCalc()); 
 *, *:before, *:after { margin: 0; padding: 0; box-sizing: border-box; } .math { background: gray; font-family: verdana, sans-serif; } .math__calc { position: absolute; left: 50%; top: 50%; transform: translateY(-50%) translateX(-50%); } .math__num { margin: 15px; color: #fff; font-size: 30px; padding-left: 100px; } .math__num--wrapper { position: relative; } .math__time { padding: 10px; background: black; color: #fff; position: absolute; right: 20px; top: 20px; border: #fff 2px solid; } .math__start { position: absolute; left: 20px; top: 20px; border: 2px solid #fff; background: #333; color: #fff; padding: 10px; } .math__multiply--symbol { position: absolute; bottom: -10px; left: 10px; font-size: 30px; } 
 <!DOCTYPE html> <html> <head> <title>Math</title> <!-- default css --> <link rel="stylesheet" type="text/css" href="css/main.css"> </head> <body class="math"> <div class="math__time">0</div> <button class="math__start">Start</button> <div class="math__calc"> <div class="math__num--wrapper"> <div class="math__num math__num--one">88</div> <span class="math__multiply--symbol">*</span> <div class="math__num math__num--two">22</div> </div> <form class="math__ans"> <input type="text" name="answer" class="math__ans--user"> </form> </div> </body> </html> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM