1

I am trying to debate whether this is a good method of handling timers in Javascript. I am using Angular, but the concept is the same as using setTimeout instead of the $timeout function Angular provides.

Old method:

$scope.timer=$scope.doTiming();
$scope.timeRemaining=30; //30 second timer;
$scope.doTiming=function(){
    return $timeout(function(){
        $scope.timeRemaining=$scope.timeRemaining-1;
        if($scope.timeRemaining<=0){
            $scope.disabledEntry=true;
            $scope.submitData();
        }else{
            $scope.timer=$scope.doTiming();
        }
    },1000);
};

Time elapsed on a 30 timer: 30.050 seconds

New Method:

var startTime=new Date().getTime, delta; //new: get current time
$scope.timeRemaining=30;
$scope.timer=$scope.doTiming();
$scope.doTiming=function(){
    return $timeout(function(){
        delta=(new Date().getTime())-startTime; //new: get delta from start time
        $scope.timeRemaining=$scope.timeRemaining-(delta/1000); //new: subtract by delta
        if($scope.timeRemaining<=0){
            $scope.disabledEntry=true;
            $scope.submitData();
        }else{
            $scope.timer=$scope.doTiming();
        }
    },1);
};

Time elapsed on a 30 timer: 30.002 seconds

Major difference is that the old way looped every second, and ticked down the timer. The new way loops constantly very quickly and measures the time based on the change in time from the start, so it has the potential to be more accurate. I am wondering if this is reasonable or not? Is this type of instant loop going to cause issues on older computers? Should I maybe use the new way with a timer of 100 instead of 1? Thoughts?

EDIT

The new way is preferable to me for reasons associated with slowed timeouts: Chrome: timeouts/interval suspended in background tabs?

Community
  • 1
  • 1
Tim Withers
  • 12,072
  • 5
  • 43
  • 67
  • 2
    Can you elaborate on why you're not simply using setTimeout/$timeout(..., 30000) to begin with? I still haven't grasped the concept of what you are trying to achieve. – fresskoma Oct 24 '13 at 20:20
  • I need to show a timer, hence the updating of the clock (`$scope.timeRemaining`) and then call a function when it is complete. – Tim Withers Oct 24 '13 at 20:22
  • Consider using https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame – hidden_4003 Oct 24 '13 at 20:24
  • http://caniuse.com/#feat=requestanimationframe - Need to support those damn IE's – Tim Withers Oct 24 '13 at 20:26
  • @TimWithers: You could use requestanimationframe and setTimeout as a fallback for browsers that don't have it :) – fresskoma Oct 25 '13 at 09:12

1 Answers1

2

In my opinion, you should do as many "timeouts" as necessary, but as few as possible. In other words, if you need to update a timer every second, trigger a timeout every second. Nobody will be able to notice a 50ms delay in a timer update (nor would anyone care), so I think it is not worth bothering the browser with additional JavaScript cycles which, for example. might be better spent updating some animation.

I can't think of a reason why this wouldn't apply to the delta-time approach as well. Worst-case scenario would be that a tab goes to the background right after a one second timeout was triggered. When the user comes back to the tab, it would then take about a second until the timer would refresh, and in that interval the user would still see the timer value from when he made the tab inactive. If that is acceptable for your use case, I wouldn't worry about increasing the interval at all :)

fresskoma
  • 25,481
  • 10
  • 85
  • 128