How to get consistent timing with requestAnimationFrame
requestAnimationFrame
's callback gets a parameter with the current timestamp. It is a high-resolution number, similar to the result of performance.now()
.
So much so, it seems to be a good practice to store the result of performance.now()
before calling requestAnimationFrame()
and compare the two timestamps to see how much time has passed.
But this yields unexpected results:
const start = performance.now();
requestAnimationFrame((timestamp) => {
console.log(timestamp - start);
// possibly negative
})
A negative number means the timestamp
is for an earlier time than start
.
How can this be?
As it turns out, the timestamp
is the time the first requestAnimationFrame
is fired for the current frame, which might happen before the performance.now()
call, hence the negative number.
This can cause problems, depending on the application logic.
How can you get more consistent timing?
Use performance.now()
only
performance.now()
in itself is a good indicator of the current time. Using that alone provides a clean and consistent way to track the time passed:
const start = performance.now();
requestAnimationFrame(() => {
console.log(performance.now() - start);
// Always positive
})
Use timestamp
only
The other solution is to ditch performance.now()
altogether and rely on the timestamp
s:
requestAnimationFrame((start) => {
requestAnimationFrame((timestamp) => {
console.log(timestamp - start);
// Always positive
})
})
This approach requires some custom logic to handle the first callback firing but otherwise is a viable solution.