97

In a modern web browser, suppose I do a setTimeout for 10 minutes (at 12:00), and 5 minutes later put the computer to sleep, what should happen when the system wakes up again? What happens if it wakes up before the 10 minutes are up (at 12:09) or much later (at 16:00)?

The reason I'm asking is because I'd like to have a new authentication token requested every 10 minutes, and I'm not sure if the browser will do the right thing and immediately request a new token if it wakes up after a long time.

Clarifications: I don't wan't to use cookies - I'm trying to build a web service here; and yes, the server will reject old and invalid tokens.

Sudhir Jonathan
  • 16,998
  • 13
  • 66
  • 90
  • 1
    Since javascript is client side, wouldnt it be better to set a cookie that can expire at a specific time? – daybreaker Jun 14 '11 at 16:32
  • http://stackoverflow.com/questions/3824754/settimeout-is-not-working-when-windows-goes-to-sleep-mode-and-then-wake-up suggests, as Andrew answered, that it won't work. – Sysyphus Jun 14 '11 at 16:39
  • @daybreaker, Sure cookies are possible, but I'm trying to create a service-based app. Same services serve the web app, iPhone and Android app. – Sudhir Jonathan Jun 14 '11 at 19:32

7 Answers7

80

As far as I've tested, it just stops and resumes after the computer wakes up. When the computer awakes the setInterval/setTimeout is unaware that any time passed.

I don't think you should rely on the accuracy of setTimeout/Interval for time critical stuff. For google chrome I discovered recently that any timeout/interval (that is shorter than 1s) will be slowed down to once a second if the tab where it's activated looses focus.

Apart from that the accuracy of timeouts/intervals is dependent on other functions running etc. In short: it's not very accurate.

So using interval and timeouts, checking the time against a starttime within the function started by it would give you better accuracy. Now if you start at 12:00, the computer goes to sleep and wakes up at 16:13 or so, checking 16:13 against 12:00 you are certain you have to renew the token. An example of using time comparison can be found here

mb21
  • 34,845
  • 8
  • 116
  • 142
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • 1
    This matches my experience as well. – jwl Jan 11 '12 at 16:48
  • I just created a quick test for this. FF 30 and Chrome 35 do a reasonable job of firing the long-running timeout as soon as the computer resumes. IE 10 reloads the page. Fiddle @ http://jsfiddle.net/Pegleg3941/8uhy8/ – EpicVoyage Jul 03 '14 at 15:29
  • `the counter ticks on from the time the computer fell asleep.`<- my experience as well. – Mahn Nov 26 '14 at 17:12
  • I wonder if this has changed since 2011. Has anyone tested this recently? – Simon East Feb 28 '16 at 09:54
  • If your interval is less than a second, Chrome 50 will only execute at a one second interval when that tab loses focus. Like @Kooilnc said, `setTimeout` and `setInterval` aren't super reliable as far as accurate time intervals go, so it's best to use them to check a date that you have cached somewhere. – ccnokes Apr 27 '16 at 20:35
  • 1
    As of 2017 (Chrome 61) this behavior of continuing the counter from falling asleep haven't changed. – Erez Cohen Oct 17 '17 at 10:47
  • 12
    I think this could be worded more clearly: when the computer awakes the setInterval/setTimeout is unaware that any time passed. – cdosborn Dec 18 '19 at 19:24
14

Compare current datetime against datetime when the page was loaded, like so:

//Force refresh after x minutes.
var initialTime = new Date();
var checkSessionTimeout = function () {
    var minutes = Math.abs((initialTime - new Date()) / 1000 / 60);
    if (minutes > 20) {
        setInterval(function () { location.href = 'Audit.aspx' }, 5000)
    } 
};
setInterval(checkSessionTimeout, 1000);
Ben
  • 584
  • 9
  • 8
  • This is a great solution. Works really well for me - thank you. – BeesonBison Jun 28 '16 at 08:26
  • In my case i have to get new token only if user is active and not idle in last hour.So from server token with expire after 1 hr but before that i have to get new one and update localStorage. If user is inactive then show session expired message else get new token silently – CyberAbhay May 14 '19 at 12:09
  • 2
    What is the reason for the inner setInterval()? Why 5 seconds? – robsch Jan 14 '20 at 13:18
11

Here is my code :

<!doctype html>
<html>

<body>
<input type="button" name="clickMe" id="colourButton" value="Start Timer" onclick="setTimeout('alert(\'Surprise!\')', 120000)"/>

</body>
<script>


</script>
</html>

I have taken three scenarios that might answer the question.

Scenario 1: At 00 Seconds click on 'Start Timer' button . At 25 seconds computer falls asleep. At 1min 40 seconds wake up computer. At 2mins Alert is displayed.

Scenario 2 : At 00 Seconds click on 'Start Timer' button . At 26 seconds computer falls asleep. At 3 mins, I wakeup the computer. The Alert is displayed.

Scenario 3 : This one is truly astounding.

<input type="button" name="clickMe" id="colourButton" value="Start Timer" onclick="setTimeout('alert(\'Surprise!\')', 600000)"/>

At 00 Seconds I click on 'Start Timer' button. At around 1min 30 seconds the computer is on hibernate mode (my pc takes a minute to initiate hibernate)

At 8 mins I turn the laptop on. At 10 mins exactly, the alert pops up.

PS: This is my first ever comment on Stack Exchange. I prefer to execute code and view results rather than infer from theory.
DannyBoi
  • 636
  • 1
  • 7
  • 23
5

Behaviour of JavaScript timers (setTimeout) in several scenarios.

  1. When the thread is free and the timeout fires: The timer is fired immediately after the timeout. It might have certain imprecision of about 0-5 ms (typical scenario).
  2. When the thread is super busy (huge loop) long enough to pass the timer timeout: The timer will be executed immediately after the thread is freed.
  3. When there is an alert: Same behaviour as 2.
  4. When the thread is paused because our laptop went to sleep: I have seen several things. But most common is total inaccuracy and ignore of the time spent during sleeping.

Since timers in JavaScript are based on CPU ticks, and the CPU is sleeping, then the timer is completely paused and resumed as 'since nothing would have happen'.

José Cabo
  • 6,149
  • 3
  • 28
  • 39
5

Based on Ben's answer, I created the following util. You can tweak the sampling duration, however I use it just like this for token refreshing:

const absoluteSetInterval = (handler, timeout) => {
  let baseTime = Date.now();
  const callHandler = () => {
    if (Date.now() - baseTime > timeout) {
      baseTime = Date.now();
      handler();
    }
  };
  return window.setInterval(callHandler, 1000);
};

const absoluteClearInterval = (handle) => window.clearInterval(handle);
Erez Cohen
  • 1,507
  • 2
  • 16
  • 25
5

The behavior is based on both the browser and the operating system. The OS handle sleep and individual apps often don't account for it.

What will most likely happen is that the OS will come back up with the same time remaining on the timer as when it was shut down. The other possibility is that it won't fire at all.

If it is really a concern, you will probably want to be better safe than sorry and store a time stamp of when the token was initialized and use setInterval to check it periodically (say twice a minute).

However, security should not be just a client side thing. Make sure that your server throws an error if an old / invalid token is used and that the Ajax behaves appropriately in response.

[edit] I agree with the other post that it might fire immediately on the next tick. Resig's blog post is very good.

Andrew Curioso
  • 2,181
  • 13
  • 24
  • The server will refuse an older token... I'm trying not to show errors to the client unnecessarily... – Sudhir Jonathan Jun 14 '11 at 18:48
  • You actually got me thinking how my own apps will behave in this case... it really is a good question. I almost want to sign into my bank and try it to see how they behave. – Andrew Curioso Jun 14 '11 at 18:52
  • They're probably using a cookie with a timestamp. I'm trying to work with cookieless services here, hence the question. – Sudhir Jonathan Jun 14 '11 at 19:30
  • Regarding Andrew's edit: It *might* fire immediately on wake-up but this depends on the browser. – EpicVoyage Jul 03 '14 at 14:45
  • IE 10, for instance, reloads the page. – EpicVoyage Jul 03 '14 at 15:32
  • *The OS handle sleep and individual apps have no say over it.* - This is misleading. Although the browser does not control going to sleep or waking up, it can receive notification of these events and decide what to do with its JS timers. – Simon East Feb 28 '16 at 10:07
  • @SimonEast You are right. I updated the answer with a bit more clarity by removing "no control". – Andrew Curioso May 27 '16 at 15:42
-3

In John Resig's blog the timers are said to be using "wall clock". I believe that the events will fire immediately after the machine is resumed because setTimeout() doesn't guarantee an execution is a specific point in time but as soon as possible after the specified interval. However, I haven't checked it myself.

Evgeny Shadchnev
  • 7,320
  • 4
  • 27
  • 30
  • 10
    You should have checked it -- it doesn't work this way, and your inference based on JR's blog is very loose. It definitely does not follow the wall clock on any system I've tested on. – jwl Jan 11 '12 at 16:48
  • 2
    FWIW, the spec says this: "wait until the Document associated with method context has been fully active for a further timeout milliseconds (**not necessarily consecutively**)". That implies that the timer could be suspended while the computer i sleeping. – geon Sep 02 '14 at 06:57