admin管理员组

文章数量:1394066

I've written a timer method which isn't working correctly. It is supposed to display the time elapsed while on a form, but it is counting by 2's or 3's instead of once per second. What could cause this behavior and how can I fix it?

My code:

function startTimer() {
  var minutes, seconds;
  
  setInterval(function () {
    if (!isPaused) {
      minutes = parseInt(timer / 60, 10);
      seconds = parseInt(timer % 60, 10);
      
      minutes = minutes < 10 ? "0" + minutes : minutes;
      seconds = seconds < 10 ? "0" + seconds : seconds;
      
      $('#TimeLabel').text("Form Time: " + minutes + ":" + seconds);
      
      ++timer;
    }
  }, 1000);
}

I've written a timer method which isn't working correctly. It is supposed to display the time elapsed while on a form, but it is counting by 2's or 3's instead of once per second. What could cause this behavior and how can I fix it?

My code:

function startTimer() {
  var minutes, seconds;
  
  setInterval(function () {
    if (!isPaused) {
      minutes = parseInt(timer / 60, 10);
      seconds = parseInt(timer % 60, 10);
      
      minutes = minutes < 10 ? "0" + minutes : minutes;
      seconds = seconds < 10 ? "0" + seconds : seconds;
      
      $('#TimeLabel').text("Form Time: " + minutes + ":" + seconds);
      
      ++timer;
    }
  }, 1000);
}

The above code displays "Form Time: 00:01" then "Form Time: 00:04" then "Form Time:00:07" ect.

Share Improve this question asked Dec 18, 2015 at 16:20 BrianLeggBrianLegg 1,7003 gold badges21 silver badges40 bronze badges 8
  • 5 setInterval (and setTimeout) are not guaranteed to be accurate in any way. They only have to wait for a minimum of the timeout you specify, and can run any time after that. This is most noticable if the tab isn't active - browsers usually heavily throttle them in those cases. – James Thorpe Commented Dec 18, 2015 at 16:23
  • I wasn't aware of that. I suppose I'll need to write a new method to subtract from the current time and calculate the elapsed time that way. Thanks – BrianLegg Commented Dec 18, 2015 at 16:24
  • 2 They should on the other hand not be several seconds of, generally it's just milliseconds. I think, from just quickly looking at the code, the issue is the way you're incrementing a number, and then dividing that to get the seconds etc. and you keep pounding the small errors in setTimeout until it bees more and more, and eventually seconds. – adeneo Commented Dec 18, 2015 at 16:30
  • While what @JamesThorpe said is undoubtedly true, your webpage would have to be very slow for it to be grouping 1 second intervals together when your webpage isn't in the background. – Stryner Commented Dec 18, 2015 at 16:30
  • 1 In case you didn't see it - @SundarSingh makes a valid point in a ment on his answer below - are you positive that startTimer is only being called once? – James Thorpe Commented Dec 18, 2015 at 16:42
 |  Show 3 more ments

4 Answers 4

Reset to default 4

Here's an example of what I came up with. It uses time so as not to be dependent on the accuracy of your setInterval. Hope this helps!

function startTimer(){
        var minutes,
            seconds;

        var startTime = new Date;

        setInterval(function(){

            var currentTime = new Date;
            seconds = currentTime.getSeconds() - startTime.getSeconds();

            if(seconds < 0){
                seconds += 60;
            }else if(seconds === 0){
                minutes = currentTime.getMinutes() - startTime.getMinutes();
            }

            console.log(minutes + ':' + seconds);

        }, 100);
}
startTimer();

It depends on the async nature of javascript and on the fact that it runs on a single thread.

There are many articles on the web who explain how the event loop works, so, I think that isn't necessary to explain it here.

You just need to keep in mind that: setTimeout or setInterval, or other similar instructions, will be executed at the first available time after the delay time passed as parameter.

So, window.setTimeout(function() { console.log('Hello World'); }, 1000); doesn't mean that will be executed exactly after 1000ms (1s).

It basically means wait for 100ms and when the event loop is free call the callback passed as parameter.

further reading

The problem may have something to do with not declaring all of your variables. When I run this version in the console, it works properly:

function startTimer() {
  var minutes, seconds, isPaused = false, timer = 1;
  
  setInterval(function () {
    if (!isPaused) {
      minutes = parseInt(timer / 60, 10);
      seconds = parseInt(timer % 60, 10);
      
      minutes = minutes < 10 ? "0" + minutes : minutes;
      seconds = seconds < 10 ? "0" + seconds : seconds;
      
      console.log("Form Time: " + minutes + ":" + seconds);
      
      timer++;
    }
  }, 1000);
}

startTimer();

I have just used code in console and found it is working fine there, code is :

  var timer =1;
  var minutes, seconds;

  setInterval(function () {

  minutes = parseInt(timer / 60, 10);
  seconds = parseInt(timer % 60, 10);

  minutes = minutes < 10 ? "0" + minutes : minutes;
  seconds = seconds < 10 ? "0" + seconds : seconds;

  console.log("Form Time: " + minutes + ":" + seconds);

  ++timer;
  }, 1000);

So there might be something which increases the value of timer or ensure that your function startTimer called only once.

本文标签: jqueryjavascript setInterval not running on timeStack Overflow