Getting smoother animated web content while reducing CPU usage
Tuesday, March 29, 2011
The web is becoming more interactive and animated day by day. Many web pages use the Canvas element to draw rich 2D content via the 2D context or modify DOM elements on the fly. These pages generally use the setTimeout or setInterval APIs to receive frequent callbacks, allowing them to redraw their content periodically, or use DHTML to move elements on the page. As 3D content drawn using the WebGL API increases in popularity, it will use similar animation techniques.
Unfortunately, setTimeout and setInterval don’t take into consideration whether the destination element, or even the tab that contains it, is actually visible. So, pages with high-frequency timers will consume CPU resources even if the tab is in the background. On laptops, netbooks, and mobile devices of all kinds, reducing CPU consumption is essential in order to prolong battery life. Additionally, excess CPU consumption by background tabs reduces the smoothness of animations on the foreground tab.
Excessive CPU consumption by timers on web pages is not a theoretical problem. We have measured web sites containing mostly static text content firing timers at a rate of over two hundred per second.
Mozilla recently introduced the experimental mozRequestAnimationFrame API, which has different semantics than setTimeout or setInterval. Instead of the developer specifying a target frame rate, the browser runs the given callback when it is ready to produce the next animated frame. The callbacks are specifically known to be relevant to the animation of the page, and don’t run too often.
An experimental webkitRequestAnimationFrame API has been upstreamed to WebKit, and is available starting in Chrome 10. This is essentially the same as mozRequestAnimationFrame, but supports an optional second argument which is the element that the callback intends to animate. This additional information will allow the browser to avoid animating elements that are not visible to the user. See this bug report for more details. Chrome doesn’t run requestAnimationFrame callbacks for background tabs at all, which dramatically reduces CPU consumption when multiple tabs containing animated content are in the same window.
The WebGL samples project contains a three dimensional graphics library that has been modified to use requestAnimationFrame rather than setTimeout or setInterval. Take a look at this library for a good example of how to convert existing timeout based animations to the new style, while preserving compatibility with browsers that don’t support requestAnimationFrame.
In the forthcoming Chrome 11 release, we plan to reduce CPU consumption even for pages that are using setTimeout and setInterval. For background tabs, we intend to run each independent timer no more than once per second. This change has already been implemented in the Chrome dev channel and canary builds. While there may be some compatibility impact for web pages, we believe that improving the user experience for the foreground tab, and increasing battery life, are problems needing to be addressed. Please send us your comments on this planned change.

6 comments:
Hachre said...
good
March 29, 2011 2:47 PM
Brandon said...
This is going to break a ton of webpages.
March 29, 2011 6:21 PM
jpvincent said...
nice to see you are more or less cooperating with Mozilla on this.
The idea of running animation "as smooth as possible" is nice, especially if the browser knows on which computer it is running (with or without battery, with good hardware acceleration or not ...)
Instead of not running the animation at all when the element or the tab is no visible, why dont you run it at least once per second ?
When animating something, you generally want it to sync with something else in the page (think of a game), and if the idea of "pausing" an entire game when the tab loses focus is great, but it should rather be an opt-in solution.
running the animation on a very low rate would avoid breaking most animation logics and save CPU anyway
March 30, 2011 1:02 AM
Kyle Matheny said...
@Brandon: How will this break webpages? I'm not sure I'll be using this API, but I don't get why it would break anything.
March 30, 2011 5:37 AM
Olivier said...
" ...we plan to reduce CPU consumption even for pages that are using setTimeout and setInterval. For background tabs, we intend to run each independent timer no more than once per second. "
Yikes. How often will you run them? Are you saying my countdown app will sound the alarm 20 seconds late? That's not good at all.
What if the tab is in the background, but the effect of the timer is visible, such as updating the Windows taskbar by changing the title of the HTML file? Or because the app uses desktop notifications when there is 1-minute left in the countdown. It would be really painful if these capabilities became unreliable in Chrome.
March 30, 2011 4:10 PM
Darin Fisher (Google) said...
@Olivier: The article says that timers in background tabs will be fired no often than once per second, so you don't have to worry about a 20 second setTimeout firing late.
March 31, 2011 2:45 PM
Post a Comment