是否定义了跨操作系统睡眠/挂起的 setTimeout 行为?

Posted

技术标签:

【中文标题】是否定义了跨操作系统睡眠/挂起的 setTimeout 行为?【英文标题】:Is the behaviour of setTimeout across an OS sleep/suspend defined? 【发布时间】:2015-06-10 01:16:19 【问题描述】:

我设置了一个setTimeout,例如 10 秒,在这 10 秒内,我暂停/休眠 PC。在觉醒时,下列哪项是正确的:-

    超时保证触发 保证不会触发超时 超时可能会触发,也可能不会触发。它是特定于浏览器的

重复 setInterval 的问题相同。是否保证(不)继续。

【问题讨论】:

引自MDN:除了“clamping”之外,当页面(或操作系统/浏览器本身)忙于其他任务时,也可以稍后触发超时。 我认为这也适用于您的情况。那么第一个选项为真。 也许您的问题应该包括:超时是在 10 秒过去后立即触发,还是在触发前 10 秒的剩余时间继续倒计时? Thomas 的回答下面似乎表明后者。 【参考方案1】:

从我目前所读到的,

    保证会开火。

但是,延迟并不能保证,并且可能取决于各种因素,并且因浏览器而异。 人们已经测试过这种行为。

您可能想查看以下cross-post。 John Resig 的 interesting read 也是如此。

【讨论】:

【参考方案2】:

简答

在规范中定义为执行。超时请求将进入排序队列并轮询,直到它可以被触发。如果系统在恢复时休眠,它将从中断处继续并恢复轮询。

长答案 可能比任何人都想知道的要多

最新的(2014 年 10 月 28 日)working-draft of the Timer's Spec 在 w3 所写的回答时,它会触发......只要操作系统在进入睡眠的过程中没有出现问题/暂停和唤醒/恢复(范围之外)。这更像是一个操作系统级别的问题,但就 w3 规范而言,它最终会触发。

setInterval(...)setTimeout(...) 都使用浏览器的window 对象实现的相同windowTimer 接口。

在这两种情况下,客户端都定义了一个间隔或超时请求,方法上下文将对其进行timer initialization steps,并在其中将其添加到活动计时器列表句柄 为计划的任务 返回。

一旦进入活动定时器列表,系统会将任务排入队列以在请求的持续时间或之后执行(同时等待具有更高优先级的其他任务)作为 CPU 负载)。如果一个任务不能保留 CPU 时间,它将轮询/等待,直到它可以。因此,如果系统在恢复时进入睡眠状态,它将从上次中断的地方继续。

为了执行任务,它的句柄必须存在于活动定时器列表中。任务运行后,如果重复标志设置为 true(如果它是使用 setInterval(...) 创建的),task 将使用相同的参数重新创建并分配相同的完全相同的 handle。换句话说,它会被添加回队列/列表中,以便在下一个间隔或之后执行。

以下是Timer 规范中关于系统从活动计时器列表中删除项目的唯一注释或备注:

一旦任务被处理,如果重复标志为假,从活动计时器列表中删除句柄条目是安全的(在此之后无法检测到条目的存在,所以它从技术上讲,无论哪种方式都无关紧要)

根据规范,如果在运行任务时它在list of active timers 中,它将按预期触发。否则中止。所以回到我的第一点,如果操作系统在恢复 task 后的睡眠/挂起过程中没有搞砸,则继续轮询。一旦它获得 CPU 时间,它的 句柄 应该仍然存在于 活动计时器列表 中,因此在被处理后将执行。

【讨论】:

很高兴为您提供帮助。 根据 Thomas 的回答,规范与现实之间存在天壤之别。【参考方案3】:

我刚刚用这个脚本测试了它:

<html>
<body>
<script>
var d = 120;
var start = new Date ();
document.write(start + " : sleeping for " + d + " seconds");
</script>
<div id='result'><div>
<script>
function cb() 
  var now = new Date ();
  document.getElementById("result").innerHTML = "" + Date () + " : callback fired after " + (now.getTime() - start.getTime()) / 1000 + " seconds";
;
window.setTimeout(cb, d * 1000);
</script>
</body>
</html>

我在 Firefox 37.0.1 和 Chromium 41.0.2272.118(64 位)中打开了该页面,然后暂停了我的机器几分钟。当我恢复时,两个浏览器都等了几分钟,即使计时器到了。示例输出(机器在Wed 15 Apr 17:52:11 BST 2015恢复):

Wed Apr 15 2015 17:49:13 GMT+0100 (BST) : sleeping for 120 seconds
Wed Apr 15 2015 17:53:47 GMT+0100 (BST) : callback fired after 273.705 seconds

【讨论】:

我们也看到了 IE11 的问题

以上是关于是否定义了跨操作系统睡眠/挂起的 setTimeout 行为?的主要内容,如果未能解决你的问题,请参考以下文章

使用尽可能少的资源,模拟挂起的 Web 应用程序的最佳方法是啥?

睡眠/暂停/休眠 Windows PC

检查挂起的 Django 迁移

如何让主管重新启动挂起的工人?

即使为挂起的操作覆盖缓冲区,WriteFile 也会成功

进程的阻塞和挂起的区别