这似乎是在一般情况下,浏览器会在某些情况下修改,甚至超出了最低钳制,实际的时间间隔setInterval
使用。 举例来说,我有以下代码:
function start() {
window.setInterval(function() {
update();
}, 1);
}
lastTime = new Date;
numFrames = 0;
lastFrames = 0;
function update() {
numFrames++;
if (new Date - lastTime >= 1000) {
lastFrames = numFrames;
numFrames = 0;
lastTime = new Date;
}
}
在这里, lastFrames
会给我们帧的过一下大约是过去的第二数目。 当在Chrome,Firefox和Safari中使用此代码不会在一毫秒运行。 当然,每个浏览器都有之间的任意最短时间setInterval
调用,所以这是可以预期的。 然而,随着网页继续运行,帧速率会不断降低,即使标签仍然集中。 我发现解决这个问题的唯一方法是让浏览器做一些事情。 这些方针的东西似乎使浏览器中运行setInterval
一样快,因为它可以:
function start() {
window.setInterval(function() {
update();
}, 1);
}
lastTime = new Date;
numFrames = 0;
lastFrames = 0;
function update() {
numFrames++;
if (new Date - lastTime >= 1000) {
lastFrames = numFrames;
numFrames = 0;
lastTime = new Date;
}
//doIntensiveLoop, processing, etc.
}
因此,我的问题是:什么是找的理由运行浏览器setInterval
接近我问它?
编辑:HTML5规范说的浏览器不应该允许的setInterval在比4ms的下一个时间间隔运行。
我想,首先,我们要问自己,我们从时间间隔功能期待:
他们必须保持上下文:在其中您不能可靠地递增计数器的时间间隔将是非常惨重
他们应该执行无论是在功能,其中有超过执行间隔优先级(这里一样,该定时器已去之前,我们再增加)
它应该有从我们的JS代码,其余的独立执行堆栈(我们不希望等待这些定时器来完成他们的业务,直到剩下开始执行);
他们应该知道他们,是无论它是多么广阔(我们希望能够使用jQuery我们的定时器功能中,例如)上下文。
因此,当马特·格里尔上面所说的,间隔由设计不准确,这主要是因为我们真的不希望他们是精确的,但要可靠在给定时间执行代码。
如果你有一个看看铬实现,你会看到的setTimeout和setInterval的实现是基于DOMTimer ::安装 ,它被传递执行上下文,动作,如果定时器是单杆
这被传递到RunloopTimer,其执行与系统计时器的帮助下环(如你在这里看到的)
(顺便说一下,铬安装最少10毫秒的时间间隔,你可以看到这里 )
该行动的每个执行是这里处理 ,其中任何确实没有声称对自上次执行过度或在一定时间限度经过的时间。
在相反,它只是断言,定时器嵌套层次不太深通过减缓这占用了过多的资源/与这个给定的间隔运行过慢计时器:
if (m_nestingLevel >= maxTimerNestingLevel)
augmentRepeatInterval(minimumInterval - repeatInterval());
}
augmentRepeatInterval简单地增加了更多毫秒的时间间隔:
void augmentRepeatInterval(double delta) { augmentFireInterval(delta); m_repeatInterval += delta; }
那么,我们能得出什么结论?
测量间隔或超时的时间精度是在浪费时间 。 你应该而且能够关心的事情是,你没有设置间隔太低,要在函数来执行的事情。 该浏览器将做它可以执行及时的间隔和超时最好的,但它并不能保证确切的时间。
该间隔执行依赖于环境,浏览器,实施,版本,背景,行为本身等等等等。 这并不意味着准确的说,如果你想确切的编程用的setTimeout或setInterval的东西,你要么疯了,现在或以后会疯掉。
你说在你的代码,当你添加重执行的职能,定时器得到了更准确。 这可能是由于不同的原因(也许它获取更多的内存,更多的独家CPU时间,更多的工人等)。 我在那很感兴趣,但你没有提供确实重尚未执行的代码。 所以,如果你想对一些答案,请提供代码,因为它很难没有它假设任何事情。
但不管它是什么,使你的时间间隔运行更及时,这是不可靠的以任何方式。 如果你开始测量在不同的系统,您将最有可能获得各种不同的结果。
UPDATE
除此之外,代码不会导致任何东西同样可以通过浏览器JS引擎优化(不执行,只执行一次,以更好的方式执行)。 让我给基于你的(所有的东西铬执行)的例子:
function start() {
window.setInterval(function() {
update();
}, 1);
}
lastTime = new Date;
numFrames = 0;
lastFrames = 0;
function update() {
console.log(new Date() - lastTime);
lastTime = new Date();
for (var i=0; i < 1000000; i++) { var k = 'string' + 'string' + 'string' }
}
你会发现,在第一次执行你击中后start
将年龄,而进一步执行(至少在WebKit的)没有。 这是因为在迭代的代码并不能改变什么,并在浏览器识别出第一执行之后,只是不执行它了。
让我们来看看它如何改变,如果执行有保持绑定到一个外部变量( k
在这种情况下):
var k;
function update() {
console.log(new Date() - lastTime);
lastTime = new Date();
for (var i=0; i < 1000000; i++) { k = 'string' + 'string' + 'string' }
}
好,下面我们就对执行时间产生一定的影响,但它仍然是相当快的。 浏览器知道for循环会一直做同样的事情,但它一旦执行它。 那么,如果迭代确实创造了巨大的字符串,例如?
var k;
function update() {
console.log(new Date() - lastTime);
lastTime = new Date();
k = '';
for (var i=0; i < 1000000; i++) { k += i.toString() }
}
这使得在受到伤害的世界浏览器,因为它必须返回数百万的字符此字符串。 我们可以让更多的痛苦?
var k;
function update() {
console.log(new Date() - lastTime);
lastTime = new Date();
k = '';
for (var i=0; i < 1000000; i++) { k = ['hey', 'hey', 'hey'].join('') }
}
此数组拼接不能被优化和缓慢而痛苦几乎窒息的任何浏览器。
所以,你的情况,重执行可能导致更多的内存被保留,并通过优化瞬间释放。 可能是新鲜空气和额外的内存和CPU的闲置一口气做你的函数跳的喜悦,但正如我所说,没有什么可靠的存在,而不必看着你重执行代码。
setInterval
和setTimeout
是不准确的,在所有的,并没有被设计成。 JavaScript是单线程的,因此setTimeout/setInterval
基本上说“拿这个代码块,并在运行队列坚持下去。当你得到它,如果有足够的时间已经过去了,然后执行它,否则它粘回到队列中,并尝试稍后再试”。
如果你有4毫秒的setInterval集,但事情在你的应用程序需要10ms的运行,那么就没有办法的setInterval可以在4毫秒曾经运行,在最好的它会拉断10ms间隔。
如果这是动画/游戏的目的,然后给requestAnimationFrame一试。 我不知道它是如何实现的,但有一点它的承诺是更准确的计时。
我能想到的一定数量的浏览器可能一段时间后,你的时间间隔减慢的原因(这是所有的猜想,但是这是你问什么,我认为):
- 其他的事情需要安排像垃圾收集等运行......这需要时间。
- 浏览器决定了您的间隔定时器被占用过多CPU或燃烧过多的电池,因此一段时间后,你节流。 有些浏览器都记录要做到这一点,当一个标签失去焦点,所以我能想象他们可能在其他时间做到这一点。
- 浏览器最初推迟,需要有利于您的间隔做其他工作,但一段时间后,它不再推迟这项工作,它需要一些时间。
问: What is the browser looking for to justify running setInterval closer to what I ask it to?
答:没有。 它确实是尽可能快的。 如果去得太快,它等待。 “成为可能”将取决于环境。
问题: However, as the page continues to run, the frame rate will continue to decrease, even if the tab is still focused.
这是一个操作系统问题。
当你的代码第一次运行在页面加载它报告250的帧率,并一直持续到操作系统决定CPU或内存分配限制到浏览器的进程。 该浏览器仍然要求在最小间隔可能(在Firefox的情况下,4毫秒)来处理这个,但操作系统可能真的不在乎。 运行时间30分钟后,它仍然有可能获得操作系统的关注,并返回到全帧率250。
只是再次重申,这有什么好做的浏览器。
尝试把这个作为你的“密集型循环”,然后试图解释的结果如何是由于浏览器:
for (var intense = 0; intense < 10000; intense++) {
var dec = intense * (5039 + intense);
for (var processing = 0; processing < intense; processing++) {
var float = dec / (processing + 1);
}
}
你应该听到的物理运行时,除非你有一个真正了不起的计算机(其中绝对没有任何一个做浏览器),你的cpu哭泣。
首先,如果你正在做的图形(该帧的谈话暗示你),你或许应该使用requestAnimationFrame而不是setInterval的。
我跑你的代码在Chrome 20和我没有看到帧速率低于244在最初几分钟。 你看到的东西有何不同? 大多数帧速率分别为249或250进来的是使用setInterval的时候,即使是在运行后在规范允许的最大值。
在很长一段时间我平均每秒247帧,一个浪费问题很容易被归因于在不合时宜的时间垃圾收集发生的历史。