据我理解,requestAnimationFrame应该尽可能接近于浏览器的帧率,大约为60fps。为确保这确实发生了,我已经记录了每个requestAnimationFrame调用的时间戳,如下:
function animate(now){
console.log(now);
window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);
Console.log数据显示,调用之间的时间间隔一直约为0.016674毫秒,因此表明帧率约为60fps(确切地说是59.9736116108912fps)。
控制台日志(样本数据):
Timestamp FPS (Current - previous) timestamp
------------------------------------------------------------
100.226 59.97361161 0.016674
116.9 59.97361161 0.016674
133.574 59.97361161 0.016674
. . .
. . .
150.248 59.97361161 0.016674
166.922 59.97361161 0.016674
183.596 59.97361161 0.016674
200.27 59.97361161 0.016674
到目前为止,requestAnimationFrame的调用在一致的时间间隔内发生,并且没有任何调用滞后/执行过快。
然而,修改animate()函数的内容以执行相对更复杂的函数会导致requestAnimationFrame调用不再那么一致。
控制台日志(样本数据):
Timestamp FPS (Current - previous) timestamp
------------------------------------------------------------
7042.73 59.97361161 0.016674
7066.278 42.4664515 0.023548
7082.952 59.97361161 0.016674
7099.626 59.97361161 0.016674
. . .
. . .
17104.026 59.97361161 0.016674
17112.84 113.4558657 0.008814
17129.514 59.97361161 0.016674
17146.188 59.97361161 0.016674
从上述数据样本可以看出,时间戳差异和帧率不再稳定,并且有时会发生过早/过晚的情况,导致帧速率不一致。如果 requestAnimationFrame 被稳定地推迟调用,我会认为由于 JavaScript 的单线程特性,驻留在 animate() 函数中的复杂代码执行时间过长,从而导致延迟的 requestAnimationFrame 调用。然而,由于 requestAnimationFrame 偶尔被过早调用,这似乎并非问题所在。
我的代码(框架):
for (var counter = 0; counter < elements.length; counter ++) //10 elements
{
//some other code
animate(element);
}
function animate(element)
{
// function invocation => performs some complex calculations and animates the element passed in as a parameter
window.requestAnimationFrame(function() { animate(element) } );
}
从上面的代码片段中可以看出,在初始的for循环内,对于每个canvas元素都会多次调用requestAnimationFrame。同时,也打算为每个canvas元素无限制地调用requestAnimationFrame。因为要执行的动画时间非常重要(在这种情况下,动画时间非常重要,应该尽可能准确),所以必须确保requestAnimationFrame调用在整个过程中始终以一致的时间间隔发生。这些时间间隔最好尽可能接近0.016674(≈ 60fps)。
关于要执行的动画的一些详细信息(对于每个canvas元素):
我有一个非常特殊的情况,需要尽可能准确地绘制闪烁/闪光动画,即canvas颜色必须以一致的速度改变,在指定的时间间隔内。例如,canvas颜色需要保持红色正好0.025秒,然后再保持蓝色0.025秒,随后又是0.025秒的红色canvas等等(动画应该无限制地进行,对于每个元素)。我的当前方法涉及跟踪动画循环中已经过去的帧数(因此,每个requestAnimationFrame调用对应于单个帧)。
由于在60Hz显示器上不能实现精确的0.025秒帧长度,每个红/蓝canvas周期都应该是“近似”的。因此,在考虑到60Hz显示器的情况下,创建一个完整的周期,其中canvas最初为红色,然后为蓝色,需要3帧(1秒/60 = 0.01666667秒* 3帧= 0.05秒=>单个完整的红/蓝周期所需的持续时间)。将0.05秒除以2即可得到所需的帧长度(即0.025秒),但由于在60Hz显示器上无法实现这一点,因此通过呈现2个红色canvas帧,再加上一个单独的蓝色帧(从而形成整个3帧周期)来近似循环。不幸的是,即使考虑了显示器的刷新率,时间也倾向于波动,导致不良的不准确性。
最后几个问题:
您能否澄清是什么原因导致了这种不一致的requestAnimationFrame行为?
是否可以应用任何优化以确保requestAnimationFrame调用在执行时具有一致的时间间隔?
如果我使用其他类型的功能(例如与setInterval()函数结合使用的Web Workers),是否可以实现更好的时间精度?
setTimeout
中编写逻辑,在requestAnimationFrame
中进行视觉更新。 - Get Off My Lawn113FPS
的帧?我无法重现。否则,1 如果有任何东西阻塞了浏览器,它将无法保持一致的帧率。2 取决于你正在做什么/是什么导致瓶颈。一些操作可以转移到WebWorker,但不是全部。3 取决于你要做什么。现在,你不应该假设任何帧率,浏览器可能(实际上应该)适应显示器的帧率。因此,使用两个不同的监视器(即使是相同的浏览器+计算机),两个用户可能会得到完全不同的结果。 - Kaiido