Unless you’re going for pinpoint animation timings it’s really pretty straightforward to create timers on a web page…or so I thought. I threw one together – a simple countdown timer that would get passed a duration, a DIV in which to display the time, a formatter function to make the time pretty, and a callback. It worked well. That is, until I tried it on my Windows Phone and happened to exit the browser while the timer was running.
I came back to the test page and the timer picked up where it left off. In some situations, this would be fine. But in my use the timer is meant to be triggered (more or less) at the same time for a group of users (via SignalR). It would be bad if one user got a text message during a 5-minute session, suspended the browser temporarily to check it, and then got an additional 30 seconds or whatever to keep on entering items after the session ended.
Was this just a Windows Phone issue? Nope. I tried it on an iPhone 5S and had the same issue. It makes sense. Phones need to conserve power whenever possible so suspending running code in a browser tab when it’s invisible is logical. I fixed this issue by setting an initiated time, using Math.round(new Date().getTime() / 1000. Each time the timer interval is called (once per second) the current time is gotten (also in seconds) and then the difference is compared to the elapsed time. And, if necessary, the timer’s remaining time is adjusted (by subtracting the suspended time span from the overall duration).
I ran into another minor issue: Hitting the test button that triggered the timer again would result in multiple intervals running. I needed to clear the current interval first. In this case, I decided to store the current interval ID in the display element, using the jQuery data function. After all, it’s the element being affected by the code.
This is the sort of thing that might be papered over easily by manipulating the UI so the triggering mechanism, e.g. a button, can’t be used more than once. But baking this little fail-safe right into the code heads off any unanticipated uses down the road. For example, perhaps the timer might be reset every time a user guesses the correct answer in a game and moves on to another question.
Here’s the complete code for the timer: