当计算机进入睡眠状态时 setTimeout 会发生什么?

在一个现代的网络浏览器中,假设我做了10分钟的 setTimeout(12:00) ,5分钟后让计算机进入睡眠状态,当系统再次醒来时会发生什么?如果它在10分钟之前醒来(12:09)或更晚(16:00)会发生什么?

我问这个问题的原因是因为我希望每10分钟就有一个新的认证令牌被请求,而且我不确定浏览器是否会做正确的事情,如果它在很长一段时间后被唤醒,它会立即请求一个新的令牌。

澄清 : 我不想使用 cookies-我正在尝试构建一个 Web 服务; 是的,服务器将拒绝旧的和无效的令牌。

30291 次浏览

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.

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.

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

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);

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.

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'.

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);