Using PC Hardware more efficiently in HTML5: New Web Performance APIs, Part 2

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.

Screen shot of Page Visibility API test drive demo

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