简体   繁体   中英

Why is my interval calling my function even though its in a variable?

I have a stopwatch that has buttons to start, stop, and reset the time. I assigned an interval to a variable to pause it using clearInterval every time I click the stop button, but my interval is calling the function even though I clicked no button. How do I fix this?

 const startButton = document.getElementById('start'); const stopButton = document.getElementById('stop'); const resetButton = document.getElementById('reset'); const myInterval = setInterval(setTime, 10); startButton.addEventListener('click', () => { setInterval(setTime, 10); }) stopButton.addEventListener('click', ()=> { clearInterval(myInterval); }) const timeUnits = ['00', '00', '00', '00']; milliSeconds = 0; seconds = 0; minutes = 0; hours = 0; function setTime() { if (minutes == 60) { hours++; minutes = 0; timeUnits[0] = hours; timeUnits[1] = 0; } else if (seconds == 60) { minutes++; seconds = 0; timeUnits[1] = minutes; timeUnits[3] = 0; } else if (milliSeconds == 100) { seconds++; milliSeconds = 0; timeUnits[2] = seconds timeUnits[3] = 0; document.getElementById('para').innerHTML = timeUnits.join(':'); } else { milliSeconds++; timeUnits[3] = milliSeconds; document.getElementById('para').innerHTML = timeUnits.join(':'); }; }
 <p id="para">00:00:00:00</p> <button id="start">Start</button> <button id="stop">Stop</button> <button id="reset">Reset</button>

You set up the interval in two places:

const myInterval = setInterval(setTime, 10);     // <-- Here (A)
startButton.addEventListener('click', () => {
  setInterval(setTime, 10);                      // <-- and here (B)
})

In spot A (auto-start on page load) you save the interval ID into myInterval so that you can later do clearInterval(myInterval) .

However, in spot B (on-demand start on "start" button click), you do not do that, so the interval set by clicking the "start" button can never be cleared.

This can be fixed by saving the interval into myInterval in both places:

let myInterval = setInterval(setTime, 10)
startButton.addEventListener('click', () => {
  myInterval = setInterval(setTime, 10)
})

Now, this created a bit of duplicate code, which is not ideal, and also there is still the problem that just clicking "start" multiple times would create multiple intervals running in parallel, overwriting the previous interval ID with the new one, making the old intervals again unclearable.

My suggestion for solving both of these issues is to create functions startInterval and stopInterval , where startInterval would also first call stopInterval before setting up a new interval, and stopInterval clearing the old one if it exists. Then you can call startInterval both on page load and on "start" button click, and stopInterval on "stop" button click:

let myInterval = null

function startInterval () {
  stopInterval()
  myInterval = setInterval(setTime, 10)
}

function stopInterval () {
  if (!myInterval) return
  clearInterval(myInterval)
  myInterval = null
}

startInterval()

startButton.addEventListener('click', startInterval)
stopButton.addEventListener('click', stopInterval)

From the wording of the question I'm not sure whether you really want to auto-start the timer though. In case you don't, you can simply remove the startInterval() line from my example (or in case of the original code, change the first assignment to let myInterval = null like in the second example).

The reason your interval is automatically starting is because you call the setInterval function when you assign the variable to begin with. To prevent this, simply define the variable with let myInterval = null; so that you get the variable, but it doesn't automatically start the interval until the start button is pressed.

The reason it's not stopping when you press the "stop" button after pressing "start" is because in your startButton click handler, you're not re-assigning the interval to the variable. So it's an interval that you can't clear because you didn't assign it to anything. The simple fix is to say myInterval = setInterval(setTime, 10) . Since you are reassigning myInterval you need to also define it with let instead of const .

 const startButton = document.getElementById('start'); const stopButton = document.getElementById('stop'); const resetButton = document.getElementById('reset'); let myInterval = null; startButton.addEventListener('click', () => { myInterval = setInterval(setTime, 10); }) stopButton.addEventListener('click', ()=> { clearInterval(myInterval); }) const timeUnits = ['00', '00', '00', '00']; milliSeconds = 0; seconds = 0; minutes = 0; hours = 0; function setTime() { if (minutes == 60) { hours++; minutes = 0; timeUnits[0] = hours; timeUnits[1] = 0; } else if (seconds == 60) { minutes++; seconds = 0; timeUnits[1] = minutes; timeUnits[3] = 0; } else if (milliSeconds == 100) { seconds++; milliSeconds = 0; timeUnits[2] = seconds timeUnits[3] = 0; document.getElementById('para').innerHTML = timeUnits.join(':'); } else { milliSeconds++; timeUnits[3] = milliSeconds; document.getElementById('para').innerHTML = timeUnits.join(':'); }; }
 <p id="para">00:00:00:00</p> <button id="start">Start</button> <button id="stop">Stop</button> <button id="reset">Reset</button>

This line:

const myInterval = setInterval(setTime, 10);

actually starts the interval.

You need to change it to this:

let myInterval;
startButton.addEventListener('click', () => {
  myInterval = setInterval(setTime, 10);
})

This ensures that everytime you press the start button the interval will be assigned to the myInterval variable again which can then be cleared by the stop button

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