窗口不在焦点时的window.setTimeout行为

时间:2013-12-19 11:54:15

标签: javascript cross-browser settimeout

这是我能想到的最简单的复制代码:

ms = 30; // 1000 ?
num = 1;
function test()
{
    num+=ms;
    document.getElementById('Submit').value = num; // Using native Javascript on purpose
    if (num < 4000)
        window.setTimeout(test, ms);
}
test()

我将ms(迭代之间的毫秒数)设置为30,运行脚本并移动到浏览器上的不同选项卡。

然后我等待大约10秒钟(脚本应该在4秒内完成)然后回到选项卡。

如果我使用Firefox,我看到脚本还没有完成,数字仍然在运行(从我离开它们的地方恢复,我猜)。

这很烦人,

但如果我将ms更改为1000并重复上述步骤,当我回到标签时,我看到脚本确实已经完成。

(脚本应该还需要4秒钟才能完成)。

即使有时,Firefox也会运行window.setTimeout,即使窗口没有焦点,有时也不会。可能取决于持续时间

另一方面,Internet Explorer不会发生这种情况。

即使选项卡没有聚焦,它也会继续运行脚本。无论我如何设置ms

  • 这是由于Firefox的一些性能考虑因素吗?

  • 到底发生了什么?

  • 为什么这些基本的东西在浏览器之间是一致的, 时下?

或者,我工作错了吗?编码是一种奇怪的方式吗?

我只是尝试以延迟的方式反复更改DOM,而不使用setInterval(因为我正在改变它自己的间隔)。

  • 最重要的是,我该如何看待这个?

我无法假设我的用户不会离开标签。

我希望允许我的用户离开页面,因为人们可能会这样。

如果一个人离开并在半小时后回来,他/她将在页面上看到无关的动画,仍然在运行。

连接到该页面的所有用户都可以看到其中一些动画。

没有必要以毫秒为单位同步它们,但只有当用户将标签/窗口置于焦点时才能启动它们。

我正在使用Firefox 25.0.1和IE 11.(Windows 7)

3 个答案:

答案 0 :(得分:6)

大多数现代浏览器(特别是在移动设备上)暂停在焦点不一致的选项卡中执行脚本以节省CPU周期(例如,这就是使requestAnimationFrame生效的原因)。在超时的情况下,较短的间隔实际上会根据浏览器供应商的需要更改为不同/更高的值。

你可以做些什么来克服这个问题(如果你真的必须知道连续执行之间的间隔)是在激活超时时设置时间戳,并将其与实际执行超时处理程序时的时间戳进行比较。请注意,当您设置动画时,最好通过考虑其他应用程序变量来计算动画对象的属性,而不是依赖于特定处理程序所具有的调用量。

您还可以将监听器附加到窗口以“(取消)关注”事件,以了解用户何时“返回”您的应用程序。在此事件处理程序中,您可以验证超时是否挂起并手动执行其回调(如果必须这样做)。

答案 1 :(得分:0)

看到区别:http://jsfiddle.net/qN6eB/

ms = 30; // 1000 ?
num = 1;
start = new Date();

function test()
{
    num+=ms;
    document.getElementById('Submit').value = num;
    if (num < 4000)
        window.setTimeout(test, ms);
    else
        document.getElementById('Time').value = new Date() - start;
}

test()



ms2 = 30; // 1000 ?
num2 = 1;
start2 = new Date();
dueTo = new Date(+new Date()+4000);

function test2()
{
    num2+=ms2;
    document.getElementById('Submit2').value = num2;
    if (new Date() < dueTo)
        window.setTimeout(test2, ms2);
    else 
        document.getElementById('Time2').value = new Date() - start2;
}
test2()

答案 2 :(得分:-1)

setTimeout对于计时不准确。因为定时器不会中断进程,所以我会等待空闲时间。我不知道浏览器是如何管理它的,但是非活动选项卡的优先级可能较低。

我可以考虑两种解决方案: - 尝试setInterval(我不确定这是否能解决你的问题) - 使用包含开头时间的Date对象,而不是递增变量,并将其与执行函数时的当前时间进行比较。

var beginTime = (new Date()).getTime();
var intervalId = setInterval(function() {
    var timePassed = (new Date()).getTime() - beginTime;
    document.getElementById('Submit').value = timePassed;
    if(timePassed >= 4000) {
        clearInterval(intervalId);
    }
}, 30);