Learn how to use the requestAnimationFrame() API for performing animations and scheduling events in a predictable manner.
The requestAnimationFrame() API is a relatively new addition to web browsers and provides a more predictable way to hook into the browser’s render cycle. It is supported by all modern browsers, including IE 10 and above.
Although not specific to animations, requestAnimationFrame() is commonly used for animating elements on a webpage.
In the past, animations were typically implemented using setTimeout() or setInterval(). With this approach, you would perform a small portion of the animation and then call setTimeout() or setInterval() to repeat the code after a few milliseconds.
Example using setTimeout():
const performAnimation = () => {
// ...
setTimeout(performAnimation, 1000 / 60);
};
setTimeout(performAnimation, 1000 / 60);
Example using setInterval():
const performAnimation = () => {
// ...
};
setInterval(performAnimation, 1000 / 60);
To stop an animation, you would need to keep track of the timeout or interval reference and clear it.
Example:
let timer;
const performAnimation = () => {
// ...
timer = setTimeout(performAnimation, 1000 / 60);
};
timer = setTimeout(performAnimation, 1000 / 60);
// ...
clearTimeout(timer);
It’s important to note that the interval of 1000/60 (approximately 16.6ms) between the performAnimation() calls is determined by the monitor’s refresh rate of 60Hz. This ensures that each frame is displayed within the available time frame.
However, a drawback of this approach is that if the browser is busy with other operations, the setTimeout calls may not make it in time for the repaint, resulting in a delayed animation or skipped frames. This can lead to a clunky animation experience for users.
To address this issue, requestAnimationFrame() provides a more efficient way to perform animations. Although the code looks similar to that of setTimeout() or setInterval(), requestAnimationFrame() works in a completely different way.
Example:
let request;
const performAnimation = () => {
request = requestAnimationFrame(performAnimation);
// animate something
};
requestAnimationFrame(performAnimation);
// ...
cancelAnimationFrame(request); // stop the animation
Unlike setTimeout() or setInterval(), requestAnimationFrame() intelligently optimizes resource consumption by pausing animations when the current window or tab is not visible. This not only enhances performance but also results in smoother animations. Browsers have also implemented throttling for setTimeout() and setInterval() to achieve similar benefits.
Here is a comparison of the timeline using setTimeout/setInterval and requestAnimationFrame():
Perfect timeline with setTimeout/setInterval:
Choppy timeline with a higher frequency using setTimeout/setInterval:
Missed frame due to delay in the event loop:
Delayed animation step and subsequent delay in rendering and painting:
Predictable timeline using requestAnimationFrame():
Using requestAnimationFrame(), all animation code runs before rendering and painting events, allowing more control over the animation process.
For more information, watch this informative video by Jake Archibald on requestAnimationFrame.