In this version of my code the timer instantly jumps to 30 seconds.
timer();
function timer() {
while (end == 0 && sec<30) {
milsec++;
if (milsec==100) {
sec++;
milsec = 0;
}
setTimeout(timer(), 10);
}
}
I tried many things before. I got the error call stack size exceeded, many times the whole page just stopped loading. Now I have come to a point where the whole thing works at least halfway, but the delay of 10 milliseconds is not working. Probably there is a simple solution to this problem but I just coudn’t figure it out…
3
Answers
Here’s one way you can implement a stopwatch, using
Date.now()
to get the number of milliseconds that have elapsed since the UNIX epoch. You can use the difference between that number and the current time, and compare that against thedurationSecs
to get the remaining time. Once there’s no time remaining, stop looping. This usesrequestAnimationFrame
to call the function approximately once every time the screen refreshes (so ~60 times per second on a standard 60 Hz monitor) because I don’t think there’s a reason to do it more often than that (especially for updating an element, which will only actually be updated once per refresh anyways). This isn’t a recursive call in the sense that it will overflow the call stack, but it’s technically recursive in the fact that it calls itself, but calling yourself inside of arequestAnimationFrame
is a standard way to do updates once every frame.Remember to read up on functions, because
setTimeout
schedules some code to run at least as many milliseconds into the future as indicated, but only at least that many milliseconds into the future. The only guarantee it makes it that your code will not run for that many milliseconds, but it says nothing about when it’ll actually run. Could be 10ms, could be 2 minutes. Both are correct bahaviour.So you can’t use it as a clock, or as a stable counter for the passage of time. If you want that, you’ll need to actually use the clock, i.e.
Date.now()
orperformance.now()
.Thankfully, writing a stopwatch doesn’t need an interval counter: all you care about is "the time when the user clicked start", and "the time the user clicked stop". Showing "a time spinner" isn’t remotely required for those two events to do what we need them to do, it’s just eye candy, so don’t do more work than is necessary to make something that looks like a number spinner.
Pick an interval that is just about meaningful to humans, like 123ms (not 10, that’s way too fast) and then schedule an interval (rather than a timeout: we don’t care if there’s interval drift or hitches etc, the page update just needs to happen "fast enough". Beyond that, we don’t care). Every time that interval triggers, you check "how much time has passed since we started" by looking at the current time, and subtracting the start time, then you update the page with that value.
Don’t increment anything during your interval, you already have all the information you need to show the passage of time.
And crucially: by doing things this way it doesn’t matter what interval we update at because the only real times that matter are the start and stop times, the page update is purely cosmetic and has nothing to do with the actual time we’re interested in. In fact, even if the page update never happens, our stop watch will still be correct because we’re checking the real times only when the user clicks our button:
Oh, there’s some things to clarify about this code…
I’m not sure if you are trying to learn JavaScript and programming in general, but I’ll try to explain as simple as possible.
First of all, JavaScript is a language based on events. In JavaScript, avoid code that can take a long time to run, because if you don’t, that may freeze your web page and your user can think that your web page is slow and buggy.
Trying to use a while loop to wait for a timer would keep the page unresponsive while the timer is running.
So, in JavaScript you should think that in another way…
Do the thing you want, then tell the browser to call back your code.
So, if you want to do something only after 30 seconds, your code can be:
But, if you want to do something each 10 milliseconds, you can do this (adapting from your original code):
Maybe you were trying to repeat an procedural code. Take this C code that may represent the thing you’re trying to do:
I did not test this C code.
C is a procedural language, that is, the code runs a line, when finished goes to the next one.
Hope that helps!