IEBlog: Using PC Hardware more efficiently in HTML5, Part 2

This IEBlog article is the second part of a two part series I wrote on using PC hardware more efficiently with new Web Performance APIs:

8 Jul 2011 12:56 PM

Web developers need API’s to efficiently take advantage of modern PC hardware through HTML5, improving the performance of Web applications, the power efficiency of the Web platform, and the resulting customer experience. The second IE10 Platform Preview supports emerging API’s from the W3C Web Performance Working Group which enable developers to make the most of the underlying hardware and use battery power more efficiently. This post details how to use Page Visibility, one of the emerging API’s, for better performance and power efficiency.

Page Visibility: adjust work depending on if the user is looking

Knowing whether a page is visible makes it possible for a developer to make better decisions about what the page does, especially around power usage and background tasks. Take a look at the Page Visibility Test Drive to see how a Web application can be aware of whether the page is visible or not to the user.

 
The Page Visibility API is now available through vendor prefixed implementations in IE10 and Chrome 13.

The developer can adjust or scale back what work the page does based on visibility. For example, if a Web based email client is visible, it may check the server for new mail every few seconds. When hidden it might scale checking email to every few minutes. Other examples include a puzzle application that can be paused when the user no longer has the game visible or showing ads only if the page is visible to the user.

The Page Visibility specification enables developers to determine the current visibility of a document and be notified of visibility changes. It consists of two properties and an event:

  • document.hidden: A boolean that describes whether the page is visible or not.
  • document.visibilityState: An attribute that returns the detailed page visibility state, e.g., PAGE_VISIBLE, PAGE_PREVIEW, etc.
  • visibilitychange: An event that gets fired any time the visibility state of the page changes.

IE10 has prefixed these attributes and event with the ‘ms’ vendor prefix.

With this interface, Web applications may choose to alter behavior based on whether they are visible to the user or not. For example, the following JavaScript shows a theoretical Web based email client checking for new emails every second without knowledge of the Page Visibility:


<!DOCTYPE html>
<html>
<head>
<title>Typical setInterval Pattern</title>
<script>
var timer = 0;
var PERIOD = 1000; // check for mail every second

function onLoad() 
{
   timer = setInterval(checkEmail, PERIOD);
}

function checkEmail() 
{
   debugMessage("Checking email at " + new Date().toTimeString());
}

function debugMessage(s) 
{
   var p = document.createElement("p");
   p.appendChild(document.createTextNode(s));
   document.body.appendChild(p);
}
</script>
</head>
<body onload="onLoad()">
</body>
</html>

Using Page Visibility, the same page can throttle back how often it checks email when the page is not visible:


<!DOCTYPE html>
<html>
<head>
<title>Visibility API Example</title>
<script>
var timer = 0;
var PERIOD_VISIBLE = 1000; // 1 second
var PERIOD_NOT_VISIBLE = 10000; // 10 seconds
var vendorHidden, vendorVisibilitychange;

function detectHiddenFeature() 
{
   // draft standard implementation
   if (typeof document.hidden != "undefined") 
   {
      vendorHidden = "hidden";
      vendorVisibilitychange = "visibilitychange";
      return true;
   }
   // IE10 prefixed implementation
   if (typeof document.msHidden != "undefined") 
   {
      vendorHidden = "msHidden";
      vendorVisibilitychange = "msvisibilitychange";
      return true;
   }
   // Chrome 13 prefixed implementation
   if (typeof document.webkitHidden != "undefined") 
   {
      vendorHidden = "webkitHidden";
      vendorVisibilitychange = "webkitvisibilitychange";
      return true;
   }
   // feature is not supported
   return false;
}

function onLoad() 
{
   // if the document.hidden feature is supported, vary interval based on visibility.
   // otherwise, just use setInterval with a fixed time.
   if (detectHiddenFeature()) 
   {
      timer = setInterval(checkEmail, document[vendorHidden] ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);
      document.addEventListener(vendorVisibilitychange, visibilityChanged);
   }
   else 
   {
      timer = setInterval(checkEmail, PERIOD_VISIBLE);
   }
}

function checkEmail() 
{
   debugMessage("Checking email at " + new Date().toTimeString());
}

function visibilityChanged() 
{
   clearTimeout(timer);
   timer = setInterval(checkEmail, document[vendorHidden] ? PERIOD_NOT_VISIBLE : PERIOD_VISIBLE);
   debugMessage("Going " + (document[vendorHidden] ? "not " : "") + "visible at " + new Date().toTimeString());
}

function debugMessage(s) 
{
   var p = document.createElement("p");
   p.appendChild(document.createTextNode(s));
   document.body.appendChild(p);
}
</script>
</head>
<body onload="onLoad()">
</body>
</html>

With the Page Visibility API, Web developers can create more power conscious Web applications. To learn about other emerging API from the W3C Web Performance Working Group supported in the second IE10 Platform Preview, read my post on the requestAnimationFrame API (link).

—Jatinder Mann, Internet Explorer Program Manager

IEBlog: Using PC Hardware more efficiently in HTML5, Part 1

In this two part IEBlog article, I discuss how to use PC hardware more efficiently with the new Web Performance APIs.

5 Jul 2011 4:43 PM

Browsers need amazing performance to deliver on the promise of HTML5 applications. Web developers need API’s to efficiently take advantage of modern PC hardware through HTML5 and build high performance Web applications with efficient power use for great, all around customer experiences. The second IE10 Platform Preview supports three emerging API’s from the W3C Web Performance Working Group which enable developers to make the most of the underlying hardware and use battery power more efficiently: requestAnimationFrame, Page Visibility and setImmediate.

Together with Google, Mozilla, and others on the W3C Web Performance Working Group and the community, we designed these new API’s over the last three months. These three API’s are a great example of how quickly new ideas can become interoperable standards developers can depend on in modern HTML5 enabled browsers.

This post details how to use the requestAnimationFrame API for better performance and power efficiency.

requestAnimationFrame API: like setTimeout, but with less wasted effort

Web developers can now schedule animations to reduce power consumption and choppiness. For example, animations today generally occur even when a Web site is in a background tab, minimized, or otherwise not visible, wasting precious battery life. Animations today are not generally aligned with the display’s refresh rate, causing choppiness in the animation. Until the requestAnimationFrame API, the Web platform did not provide an efficient means for Web developers to schedule graphics timers for animations.

Let’s take a look at an example. Most animations use a JavaScript timer resolution of less than 16.7ms to draw animations, even though most monitors can only display at 16.7ms periods (at 60Hz frequency). The first graph below represents the 16.7ms display monitor frequency. The second graph represents a typical setTimout or setInterval of 10ms. In this case, the consumer will never see every third draw because another draw will occur before the display refreshes. This overdrawing results in choppy animations as every third frame is being lost. Reducing the timer resolution can also negatively impact battery life by up to 25%.

Figure: At top, each arrow represents a monitor refresh at 16.7ms periods. Below is a 10ms page redraw cycle. Every third redraw is wasted because the monitor will never show it. The result is choppy animations and wasted battery.

The requestAnimationFrame API is similar to the setTimeout and setInterval API’s developers use today. The key difference is that it notifies the application when the browser needs to update the screen, and only when the browser needs to update the screen. It keeps Web applications perfectly aligned with the browser’s painting, and uses only the necessary amount of resources.

If you take a look at this requestAnimationFrame example, you will notice that even though the animations look identical, the clock drawn with requestAnimationFrame is always more efficient in power consumption, background interference and CPU efficiency than the setTimeout clock.


The requestAnimationFrame animation (right) is more efficient in power consumption, background interference and CPU efficiency than the setTimeout animation (left).

It is a simple change to upgrade your current animations to use this new API. If you are using setTimeout(draw, PERIOD); in your code, you can replace it with requestAnimationFrame. The requestAnimationFrame API is the furthest along of these three API’s with vendor prefixed interoperable implementations available starting with Firefox 4, Chrome 13, and IE10.

Remember, requestAnimationFrame only schedules a single callback, like setTimout, and if subsequent animation frames are needed, then requestAnimationFrame will need to be called again from within the callback. In this Platform Preview, IE implements the API with a vendor prefix like other browsers. Here is an example of how to write cross-browser mark-up that is future proof:


// Future-proof: when feature is fully standardized
if (window.requestAnimationFrame) window.requestAnimationFrame(draw);
// IE implementation
else if (window.msRequestAnimationFrame) window.msRequestAnimationFrame(draw);
// Firefox implementation
else if (window.mozRequestAnimationFrame) window.mozRequestAnimationFrame(draw);
// Chrome implementation
else if (window.webkitRequestAnimationFrame) window.webkitRequestAnimationFrame(draw);
// Other browsers that do not yet support feature
else setTimeout(draw, PERIOD);

Thank you, to everyone in the W3C Web Performance Working Group for helping design these APIs, and thanks to other browsers, for starting to implement these APIs with an eye towards interoperability. With these APIs, Web developers can create a faster and more power conscious Web.

—Jatinder Mann, Internet Explorer Program Manager