Timing control for script-based animations ("requestAnimationFrame")
The top row represents the 16.7ms display frequency displayed on most monitors and the bottom row represents a typical setTimeout of 10ms. Every third draw cannot be painted (indicated by the red arrow) because another draw request occurs before the display refresh interval. This overdrawing results in choppy animations because every third frame is lost. This timer resolution reduction can also negatively impact battery life, and reduce performance of other apps.
The requestAnimationFrame method (defined in the World Wide Web Consortium (W3C)'s Timing control for script-based animations specification) can solve the lost frame problem because it enables apps to be notified when (and only when) the browser needs to update the page display. As a result, apps are perfectly aligned with the browser painting interval and use only the appropriate amount of resources. Switching from setTimeout to requestAnimationFrame is easy, as they both schedule a single callback. For continued animation, call requestAnimationFrame again after the animation function has been called.
To use this new API, you just call requestAnimationFrame using a callback function. The timing is handled by the system. If you're currently using setTimeout to drive your animation timing, like this:
You can replace setTimeout with requestAnimationFrame, as shown here:
This takes care of your first repaint. To keep the animation going, call requestAnimationFrame again from within your callback function (shown as renderLoop here).
This examples starts by saving the <div> element to a global variable using getElementById. The renderLoop() function is called to start the animation. After the <div> element is repositioned, requestAnimationFrame is called again to set up for the next move. This continues until you close the browser or click the <div> element.
You can use the callback function to animate almost anything, for example, SVG, Canvas, or as we show here, CSS properties. The callback function has one incoming time parameter, which represents the time the callback function is called. This is a DOMHighResTimeStamp, a high resolution time measured from the beginning of the navigation of the page. DOMHighResTimeStamp is measured in milliseconds accurate to a thousandth of a millisecond. This time value isn't directly comparable with Date.now(), which measures time in milliseconds since 01 January 1970. If you want to compare the time parameter with the current time, use window.performance.now for the current time. Changing the time value from DOMTimeStamp to DOMHighResTimeStamp was a late breaking change in the latest Editors Draft of the W3C Timing control for script-based animation specification, and some vendors might still implement it as DOMTimeStamp. Earlier versions of the W3C specification used the DOMTimeStamp, which allowed you to use Date.now for the current time.
As mentioned earlier, some browser vendors might still implement the DOMTimeStamp parameter, or haven't implemented the window.performance.now timing function. Because the W3C specification isn't yet final, other browser manufacturers have created their own prefixed implementations of requestAnimationFrame and cancelAnimationFrame. This example provides a version of our animation program that works across several browsers and uses time to move the <div> element.
This example is an updated version of a sample from the W3C specification, with vender prefixed elements added. The example additionally tests for window.performance.now, and if it isn't supported, uses Date.now to get the current time. If requestAnimationFrame and cancelAnimationFrame aren't supported, then setTimeout and clearTimeout are used. This gives compatibility for earlier versions of the browser.
- W3C Web Performance: Continuing Performance Investments
- Web Performance APIs Rapidly Become W3C Candidate Recommendations
- Moving the Stable Web Forward in IE10 Release Preview
- The Year in Review: W3C Web Performance Working Group
- Using PC Hardware more efficiently in HTML5: New Web Performance APIs, Part 1