admin管理员组文章数量:1327885
From my understanding, requestAnimationFrame should run as close as possible to the browser's frame rate, which is approximately 60fps. To ensure that this is indeed taking place, I have been logging timestamps for each requestAnimationFrame invocation like so:
function animate(now){
console.log(now);
window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);
Console.log data shows that invocations are consistently taking place approximately 0.016674 milliseconds apart, thus indicating that the frame rate is ≈ 60fps (59.9736116108912fps to be exact).
Console.logs (sample data):
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
Up to this point, requestAnimationFrame invocations are occurring at consistent time intervals, and no invocation lags behind/executes too fast.
However, modifying the contents of the animate() function to execute a relatively more plex function, results in requestAnimationFrame invocations which are not as consistent.
Console.logs (sample data):
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
As can be seen in the above data sample, timestamp differences and frame rates are no longer steady, and sometimes occur too soon/too late, resulting in inconsistent frame rates. Had requestAnimationFrame been consistently invoked late, I would have assumed that due to JavaScript's single-threaded nature, plex code residing in the animate() function is taking too long to execute, and thus results in a delayed requestAnimationFrame invocation. However, since requestAnimationFrame is occasionally being invoked too early, this does not seem to be the case.
My code (skeleton):
for (var counter = 0; counter < elements.length; counter ++) //10 elements
{
//some other code
animate(element);
}
function animate(element)
{
// function invocation => performs some plex calculations and animates the element passed in as a parameter
window.requestAnimationFrame(function() { animate(element) } );
}
As can be seen in the above code snippet, requestAnimationFrame is being invoked multiple times for each element, within the initial for loop. RequestAnimationFrame invocations are also intended to go on infinitely, for each of the elements. Since the animation to be performed is highly time-critical (animation timing is very important in this scenario and should be as accurate as possible), it is essential that requestAnimationFrame invocations occur at consistent time intervals throughout. These time intervals should ideally be as close as possible to 0.016674 (≈ 60fps).
Some detail regarding animation to be performed (on each canvas element):
I have a very specific situation, for which I am required to draw a blinking/flashing animation as accurately as possible with respect to time, i.e. canvas colour will have to change at a consistent rate, for the specified time interval. Therefore, for instance, canvas colour needs to stay red for exactly 0.025 seconds, followed by another 0.025 seconds where canvas colour is set to blue, which are then followed by another 0.025s where canvas is red and so on...(animation should go on infinitely, for each of the elements). My current approach involves keeping track of the number of frames which have elapsed within the animation loop itself (thus, each requestAnimationFrame invocation corresponds to a single frame).
Since on a 60Hz monitor an exact frame length of 0.025 seconds cannot be achieved, each red/blue canvas cycle should be "approximated". So, taking into consideration a 60Hz monitor, creating a plete cycle, where the canvas is initially red, followed by blue, a total of 3 frames would be required (1 sec/60 = 0.01666667 seconds * 3 frames = 0.05 seconds => the desired duration for a single, plete red/blue cycle). Dividing 0.05 seconds by 2 would give the desired frame length (which is 0.025 seconds), however since this cannot be achieved on a 60Hz monitor, the cycle is approximated by presenting 2 red canvas frames, followed by a single blue frame (thus forming the entire 3-frame cycle). Unfortunately, even when taking the monitor's refresh rate into consideration, the timing tends to fluctuate, resulting in undesirable inaccuracies.
Final questions:
Would you be able to clarify what is causing this inconsistent requestAnimationFrame behaviour?
Can any optimisations be applied to ensure that requestAnimationFrame invocations are executed at consistent time intervals?
Can better timing accuracy be achieved if I use some other kind of functionality (say, web workers in bination with the setInterval() function)?
From my understanding, requestAnimationFrame should run as close as possible to the browser's frame rate, which is approximately 60fps. To ensure that this is indeed taking place, I have been logging timestamps for each requestAnimationFrame invocation like so:
function animate(now){
console.log(now);
window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);
Console.log data shows that invocations are consistently taking place approximately 0.016674 milliseconds apart, thus indicating that the frame rate is ≈ 60fps (59.9736116108912fps to be exact).
Console.logs (sample data):
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
Up to this point, requestAnimationFrame invocations are occurring at consistent time intervals, and no invocation lags behind/executes too fast.
However, modifying the contents of the animate() function to execute a relatively more plex function, results in requestAnimationFrame invocations which are not as consistent.
Console.logs (sample data):
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
As can be seen in the above data sample, timestamp differences and frame rates are no longer steady, and sometimes occur too soon/too late, resulting in inconsistent frame rates. Had requestAnimationFrame been consistently invoked late, I would have assumed that due to JavaScript's single-threaded nature, plex code residing in the animate() function is taking too long to execute, and thus results in a delayed requestAnimationFrame invocation. However, since requestAnimationFrame is occasionally being invoked too early, this does not seem to be the case.
My code (skeleton):
for (var counter = 0; counter < elements.length; counter ++) //10 elements
{
//some other code
animate(element);
}
function animate(element)
{
// function invocation => performs some plex calculations and animates the element passed in as a parameter
window.requestAnimationFrame(function() { animate(element) } );
}
As can be seen in the above code snippet, requestAnimationFrame is being invoked multiple times for each element, within the initial for loop. RequestAnimationFrame invocations are also intended to go on infinitely, for each of the elements. Since the animation to be performed is highly time-critical (animation timing is very important in this scenario and should be as accurate as possible), it is essential that requestAnimationFrame invocations occur at consistent time intervals throughout. These time intervals should ideally be as close as possible to 0.016674 (≈ 60fps).
Some detail regarding animation to be performed (on each canvas element):
I have a very specific situation, for which I am required to draw a blinking/flashing animation as accurately as possible with respect to time, i.e. canvas colour will have to change at a consistent rate, for the specified time interval. Therefore, for instance, canvas colour needs to stay red for exactly 0.025 seconds, followed by another 0.025 seconds where canvas colour is set to blue, which are then followed by another 0.025s where canvas is red and so on...(animation should go on infinitely, for each of the elements). My current approach involves keeping track of the number of frames which have elapsed within the animation loop itself (thus, each requestAnimationFrame invocation corresponds to a single frame).
Since on a 60Hz monitor an exact frame length of 0.025 seconds cannot be achieved, each red/blue canvas cycle should be "approximated". So, taking into consideration a 60Hz monitor, creating a plete cycle, where the canvas is initially red, followed by blue, a total of 3 frames would be required (1 sec/60 = 0.01666667 seconds * 3 frames = 0.05 seconds => the desired duration for a single, plete red/blue cycle). Dividing 0.05 seconds by 2 would give the desired frame length (which is 0.025 seconds), however since this cannot be achieved on a 60Hz monitor, the cycle is approximated by presenting 2 red canvas frames, followed by a single blue frame (thus forming the entire 3-frame cycle). Unfortunately, even when taking the monitor's refresh rate into consideration, the timing tends to fluctuate, resulting in undesirable inaccuracies.
Final questions:
Would you be able to clarify what is causing this inconsistent requestAnimationFrame behaviour?
Can any optimisations be applied to ensure that requestAnimationFrame invocations are executed at consistent time intervals?
Can better timing accuracy be achieved if I use some other kind of functionality (say, web workers in bination with the setInterval() function)?
-
You should be doing your logic within a
setTimeout
and visual updates withinrequestAnimationFrame
– Get Off My Lawn Commented Aug 27, 2019 at 20:10 - 1 @GetOffMyLawn However isn't setTimeout highly inaccurate? From tests performed, as well as a number of online sources it appears to be so. The same applies for setInterval. – Questionnaire Commented Aug 27, 2019 at 20:13
-
The interval starts
x
milliseconds after the callback finishes executing, so tasks that vary in plication can delay or speed up when the callback gets called again. – Get Off My Lawn Commented Aug 27, 2019 at 20:23 -
1
What browser were you using to produce this
113FPS
frame? Can't repro this. Otherwise 1 if anything blocks the browser, it won't be able to maintain a consistent frame rate. 2, depends on what you are doing / what is causing the bottleneck. Some operations could be offloaded to a WebWorker, but not all. 3 depends what you are trying to do exactly. Now, you should not assume any frame rate, browsers may (and actually should) adapt it to the monitor's frame rate. So two users may have pletely different results using two different monitors (even on the same browser+puter). – Kaiido Commented Aug 29, 2019 at 7:59 - 1 When you have such short drops in framerate and you don't know why, is GC always a good guess. – Thomas Commented Sep 3, 2019 at 23:24
1 Answer
Reset to default 5 +25requestAnimationFrame will "do its best" to run at a "consistent" frame rate. That doesn't guarantee a 60fps; it just states that it will animate as fast as it can.
The method in a nutshell allows you to execute code on the next available screen repaint, taking the guess work out of getting in sync with the user's browser and hardware readiness to make changes to the screen.
We enter a callback function containing the code we wish to run, and requestAnimationFrame() will run it when the screen is ready to accept the next screen repaint.
In order to keep constant your animation you have to calculate the data in the callback reputing values against the actual delta, not presuming a constant FPS.
Eg:
function moveit(timestamp, el, dist, duration){
//if browser doesn't support requestAnimationFrame, generate our own timestamp using Date:
var timestamp = timestamp || new Date().getTime()
var runtime = timestamp - starttime
var progress = runtime / duration
progress = Math.min(progress, 1)
el.style.left = (dist * progress).toFixed(2) + 'px'
if (runtime < duration){ // if duration not met yet
requestAnimationFrame(function(timestamp){ // call requestAnimationFrame again with parameters
moveit(timestamp, el, dist, duration)
})
}
}
requestAnimationFrame(function(timestamp){
starttime = timestamp || new Date().getTime() //if browser doesn't support requestAnimationFrame, generate our own timestamp using Date
moveit(timestamp, adiv, 400, 2000) // 400px over 1 second
})
本文标签: javascriptRequestAnimationFrame speeds upslows down periodicallyStack Overflow
版权声明:本文标题:javascript - RequestAnimationFrame speeds upslows down periodically - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742228026a2436690.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论