Understanding the Real-World Performance of your Web Application Across IE11 and Other Browsers


Together with Google, Mozilla, Microsoft, and other community leaders, the W3C Web Performance working group has standardized the Navigation Timing, Resource Timing, User Timing, and Performance Timeline interfaces to help you understand the real-world performance of navigating, fetching resources, and running scripts in your Web application. You can use these interfaces to capture and analyze how your real-world customers are experiencing your Web application, instead of relying on synthetic testing, which tests the performance of your application in an artificial environment. With this timing data, you can identify opportunities to improve the real-world performance of your Web applications. All of these interfaces are supported in IE11. Check out the Performance Timing Test Drive to see these interfaces in action.

The Performance Timing testdrive lets you try out the Timing APIs.
The Performance Timing Test Drive lets you try out the Timing APIs.

Performance Timeline

The Performance Timeline specification has been published as a W3C Recommendation and is fully supported in IE11 and Chrome 30. Using this interface, you can get an end to end view of time spent during navigating, fetching resources, and executing scripts running in your application. This specification defines both the minimum attributes all performance metrics need to implement and the interfaces developers can use to retrieve any type of performance metric.

All performance metrics must support the following four attributes:

  • name. This attribute stores a unique identifier for the performance metric. For example, for a resource, it will be the resolved URL of the resource.
  • entryType. This attribute stores the type of performance metric. For example, a metric for a resource would be stored as “resource.”
  • startTime. This attribute stores the first recorded timestamp of the performance metric.
  • duration. This attribute stores the end-to-end duration of the event being recorded by the metric.

All of the timing data is recorded in high resolution time using the type DOMHighResTimeStamps, defined in the High Resolution Time specification. Unlike DOMTimeStamps which measure time values in milliseconds from 01 January, 1970 UTC, the high resolution time value is measured in at least microsecond resolution from the start of navigation of the document. For example, if I check the current time using performance.now(), the high resolution time analogous for Date.now(), I would get the following interpretation of the current time:

> performance.now();

4038.2319370044793

 

> Date.now()

1386797626201

This time value also has the benefit of not being impacted by clock skew or adjustments. You can explore the What Time Is It Test Drive to understand the use of high resolution time.

You can use the following interfaces to retrieve a list of the performance metrics recorded at the time of the call. Using the startTime and duration, as well as any other attributes provided by the metric, you can obtain an end-to-end timeline view of your page performance as your customers had experienced.

PerformanceEntryList getEntries();

PerformanceEntryList getEntriesByType(DOMString entryType);

PerformanceEntryList getEntriesByName(DOMString name, optional DOMString entryType);

The getEntries method returns a list of all of the performance metrics on the page, whereas the other methods return specific items based on the name or type. We expect most developers will just use JSON stringify on the entire list of metrics and send the results to their server for analysis rather than on the client.

Let’s take a closer look at each of the different performance metrics: navigation, resource, marks, and measures.

Navigation Timing

The Navigation Timing interfaces provide accurate timing measurements for each of the phases of navigating to your Web application. The Navigation Timing L1 specification has been published as a W3C Recommendation, with full support since IE9, Chrome 28, and Firefox 23. The Navigation Timing L2 specification is a First Public Working Draft and is supported by IE11.

With Navigation Timing, developers can not only get the accurate end-to-end page load time, including the time it takes to get the page from the server, but also get the breakdown of where that time was spent in each of the networking and DOM processing phases: unload, redirect, app cache, DNS, TCP, request, response, DOM processing, and the load event. The script below uses Navigation Timing L2 to get this detailed information. The entry type for this metric is “navigation,” while the name is “document.” Check out a demo of Navigation Timing on the IE Test Drive site.

<!DOCTYPE html>

<html>

<head></head>

<body>

<script>

 function sendNavigationTiming() {

   var nt = performance.getEntriesByType(‘navigation’)[0];

   var navigation = ‘ Start Time: ‘ + nt.startTime + ‘ms’;

   navigation += ‘ Duration: ‘ + nt.duration + ‘ms’;

   navigation += ‘ Unload: ‘ + (nt.unloadEventEnd – nt.unloadEventStart) + ‘ms’;

   navigation += ‘ Redirect: ‘ + (nt.redirectEnd – nt.redirectStart) + ‘ms’;

   navigation += ‘ App Cache: ‘ + (nt. domainLookupStart – nt.fetchStart) + ‘ms’;

   navigation += ‘ DNS: ‘ + (nt.domainLookupEnd – nt.domainLookupStart) + ‘ms’;

   navigation += ‘ TCP: ‘ + (nt.connectEnd – nt.connectStart) + ‘ms’;

   navigation += ‘ Request: ‘ + (nt.responseStart – nt.requestStart) + ‘ms’;

   navigation += ‘ Response: ‘ + (nt.responseEnd – nt.responseStart) + ‘ms’;

   navigation += ‘ Processing: ‘ + (nt.domComplete – nt.domLoading) + ‘ms’;

   navigation += ‘ Load Event: ‘ + (nt.loadEventEnd – nt.loadEventStart) + ‘ms’;

   sendAnalytics(navigation);

 }

</script>

</body>

</html>

By looking at the detailed time spent in each of the network phases, you can better diagnose and fix your performance issues. For example, you may consider not using a redirection if you find redirect time is high, use a DNS caching service if DNS time is high, use a CDN closer to your users if request time is high, or GZip your content if response time is high. Check out this video for tips and tricks on improving your network performance.

The main difference between the two Navigation Timing specification versions is in how timing data is accessed and in how time is measured. The L1 interface defines these attributes under the performance.timing object and in milliseconds since 01 January, 1970. The L2 interface allows the same attributes to be retrieved using the Performance Timeline methods, enables them to be more easily placed in a timeline view, and records them with high resolution timers.

Prior to Navigation Timing, developers would commonly try to measure the page load performance by writing JavaScript in the head of the document, like the below code sample. Check out a demo of this technique on the IE Test Drive site.

<!DOCTYPE html>

<html>

<head>

<script>

    var start = Date.now();

 

    function sendPageLoad() {

        var now = Date.now();

        var latency = now – start;

        sendAnalytics(‘Page Load Time: ‘ + latency);

    }

 

</script>

</head>

<body onload=’sendPageLoad()’>

</body>

</html>

However, this technique does not accurately measure page load performance, because it does not include the time it takes to get the page from the server. Additionally, running JavaScript in the head of the document is generally a poor performance pattern.

Resource Timing

Resource Timing provides accurate timing information on fetching resources in the page. Similar to Navigation Timing, Resource Timing provides detailed timing information on the redirect, DNS, TCP, request, and response phases of the fetched resources. The Resource Timing specification has been published as a W3C Candidate Recommendation with support since IE10 and Chrome 30.

The following sample code uses the getEntriesByType method to obtain all resources initiated by the <img> element. The entry type for resources is “resource,” and the name will be the resolved URL of the resource. Check out a demo of Resource Timing on the IE Test Drive site.

<!DOCTYPE html>

<html>

  <head>

  </head>

  <body onload=’sendResourceTiming()’>

    <img src=’http://some-server/image1.png’>

    <img src=’http://some-server/image2.png’>

 

    <script>

        function sendResourceTiming()

        {

            var resourceList = window.performance.getEntriesByType(‘resource’);

            for (i = 0; i < resourceList.length; i++)

            {

                if (resourceList[i].initiatorType == ‘img’)

                {

                    sendAnalytics(‘Image Fetch Time: ‘ + resourceList[i].duration);

                }

            }

        }

    </script>

  </body>

</html>

For security purposes, cross-origin resources only show their start time and duration; the detailed timing attributes are set to zero. This helps avoid issues of statistical fingerprinting, where someone can try to determine your membership in an organization by confirming whether a resource is in your cache by looking at the detailed network time. The cross origin server can send the timing-allow-origin HTTP header if it wants to share timing data with you.

User Timing

User Timing provides detailed timing information on the execution of scripts in your application, complementing Navigation Timing and Resource Timing which provide detailed network timing information. User Timing allows you to display your script timing information in the same timeline view as your network timing data to get an end to end understanding of your app performance. The User Timing specification has been published as a W3C Recommendation, with support since IE10 and Chrome 30.

The User Timing interface defines two metrics used to measure script timing: marks and measures. A mark represents a high resolution time stamp at a given point in time during your script execution. A measure represents the difference between two marks.

The following methods can be used to create marks and measures:

void mark(DOMString markName);

void measure(DOMString measureName, optional DOMString startMark, optional DOMString endMark);

Once you have added marks and measures to your script, you can retrieve the timing data by using the getEntry, getEntryByType, or getEntryByName methods. The mark entry type is “mark,” and the measure entry type is “measure.”

The following sample code uses the mark and measure methods to measure the amount of time it takes to execute the doTask1() and doTask2() methods. Check out a demo of User Timing on the IE Test Drive site.

<!DOCTYPE html>

<html>

  <head>

  </head>

  <body onload=’doWork()’>

    <script>

        function doWork()

        {

            performance.mark(‘markStartTask1’);

            doTask1();

            performance.mark(‘markEndTask1’);

           

            performance.mark(‘markStartTask2’);

            doTask2();

            performance.mark(‘markEndTask2’);

 

            performance.measure(‘measureTask1’, ‘markStartTask1’, ‘markEndTask1’);

            performance.measure(‘measureTask2’, ‘markStartTask2’, ‘markEndTask2’);

 

            sendUserTiming(performance.getEntries());

        }

    </script>

  </body>

</html>

We want to thank everyone in the W3C Web Performance Working Group for helping design these interfaces and browsers vendors for working on implementing this interface with an eye towards interoperability. With these interfaces, Web developers can truly start to measure and understand what they can do to improve the performance of their applications.

Try out the performance measurement interfaces with your Web apps in IE11, and as always, we look forward to your feedback via Connect.

Thanks,

Jatinder Mann, Internet Explorer Program Manager

Comments (9)

  1. Very very cool. I don't suppose any of these objects are readily exposed for consumption by browser extensions?

  2. Real McCoy says:

    Thanks. Few suggestions on a very topic:

    Can you guys please get help from VC team, for the guy who is writing (Khronos) WebGL? I don't know his name, but I heard somewhere that he wrote WebGL in C89/C99 instead of C++ and he worked on this alone. Microsoft get tons of bad rep due to Internet Explorer issues (performance, conformance, optimization, crashes..) over the past two decades. Please get help from your fellow colleagues and bring WebGL 1.0/1.1 to IE11 via update (current supported version in IE11 is 0.9.2 while other browsers are at 1.0/1.1 mark).

    Also, to C/C++ compiler teams, talk some sense into JS compiler (aka Chakra).  Identify the common constructs, such as Try/Catch, and bring the super cool magical optimizations to JS compiler too. Here is a test bed:

    http://www.newilk.com/…/SpeedTest1

    If Chrome and Firefox can do all of it under 10ms, I am super certain that Microsoft compiler teams can make it to perform better than that… 1ms!! Billions of people use IE daily.. even more than VC compilers.. so yes it is highly imperative in that regard. And for the compiler optimizer fanatic, how can you let it happen on your watch… 😎

    Then there is this known basic DOM manipulation operation test, written by "Ian Hickson" back in 2003 http://www.newilk.com/…/DomManipulation. Unfortunately, Windows'/IE's JS engine till date is performing (super well compared to the predeceasing versions but) worse when compared to the edge versions of other browsers.

    Guys please put bureaucracy/politics aside and do this for the love of technology! As VC guys are (hopefully) moving forward for branch-prediction optimizations (stackoverflow.com/a/11227902/863980) and some others in VC compilers, please spare some love to JavaScript too. Optimize it to the utmost of your abilities once forever. See how Clang and V8 guys together reinvigorated bridges/relationship between two languages at Google..

    "Many of the great achievements of the world were accomplished by tired and discouraged men who kept on working."

    Thank you!

  3. The Deeds says:

    In addition to Real McCoy's request to seek support from VC and Visual Studio teams, here are some bug reports pertaining to F12 developer tools where VS team can stand tall:

    791981: F12 developer tools: Cannot select and paste multiple CSS rules and properties.

    //connect.microsoft.com/IE/feedback/details/791981/f12-developer-tools-cannot-select-and-paste-multiple-css-rules-and-properties

    792543: F12 developer tools: CSS rule copies with 3 space indentation instead of 4.

    //connect.microsoft.com/IE/feedback/details/792543/f12-developer-tools-css-rule-copies-with-3-space-indentation-instead-of-4

    797447: F12 developer tools: "Copy elements with styles" ignores @font-face.

    //connect.microsoft.com/IE/feedback/details/797447/f12-developer-tools-copy-elements-with-styles-ignores-font-face

    798009: F12 developer tools: quick glance at elements' dimensions (height, width, border-radius) and images preview.

    //connect.microsoft.com/IE/feedback/details/798009/f12-developer-tools-quick-glance-at-elements-dimensions-height-width-border-radius-and-images-preview

    798021: F12 developer tools: Color picker and Ruler tools.

    //connect.microsoft.com/IE/feedback/details/798021/f12-developer-tools-color-picker-and-ruler-tools

    798046: F12 developer tools: Visual Studio 2012+ like priority color palette.

    //connect.microsoft.com/IE/feedback/details/798046/f12-developer-tools-visual-studio-2012-like-priority-color-palette

    800084: F12 developer tools: tools: Ability to toggle element states.

    //connect.microsoft.com/IE/feedback/details/800084/f12-developer-tools-ability-to-toggle-element-states

    801923: F12 developer tools: media query overrides for debugging layout.

    //connect.microsoft.com/IE/feedback/details/801923/f12-developer-tools-media-query-overrides-for-debugging-layout

    805145: F12 developer tools: Ability to quick edit start-tag and its corresponding end-tag.

    //connect.microsoft.com/IE/feedback/details/805145/f12-developer-tools-ability-to-quick-edit-start-tag-and-its-corresponding-end-tag

    805163: F12 developer tools: Change numeric values using keyboard up/down keys.

    //connect.microsoft.com/IE/feedback/details/805163/f12-developer-tools-change-numeric-values-using-keyboard-up-down-keys

    811024: F12 developer tools: Disconnected with browser window.

    //connect.microsoft.com/IE/feedback/details/811024/f12-developer-tools-disconnected-with-browser-window

  4. Sachin Joseph says:

    See this suite of tests: http://www.newilk.com/testing

  5. Sachin Joseph says:

    IE 11 also trails behind other browsers in these tests (Canvas, SVG)

    1.   paperjs.org/…/voronoi

    2.   paperjs.org/…/spiral-raster (very much behind Google Chrome)

    3.   paperjs.org/…/q-bertify

    4.   paperjs.org/…/path-intersections (doesn't work as expected)

  6. NumbStill says:

    Your examples lack spaces. DOCTYPEhtml instead of DOCTYPE html, bodyonclick instead of body onclick and so. Since you expect people to work with your examples and copy them, make sure the are actually working.

  7. Joe W says:

    Please stop releasing new IE products that are not compatible across Microsoft's own fleet of software – namely Microsoft CRM.  "Capability View" settings are no way for me to keep my customers up and running – it is a manual operation, and quite frankly is such a band-aide.

    There should be no reason that out-of-the-box IE 11 shouldn't support Microsoft CRM.  Period.  You will not convince anyone otherwise.

  8. Jatinder Mann [MSFT] says:

    @EricLaw: I believe these APIs are available to our COM interfaces. Let me check and get back to you.

    @NumbStill: Looks like the code sample spacing was messed up by our Blog Tools. I've fixed the samples now. Thanks!

  9. Sam says:

    I fixed your code for you:

    <!doctype html>

    <html>

    <head></head>

    <body>

    <script>

    function sendNavigationTiming(){

    var nt = performance.getEntriesByType('navigation')[0];

    var navigation = ' Start Time: ' + nt.startTime + 'ms';

    navigation += ' Duration: ' + nt.duration + 'ms';

    navigation += ' Unload: ' + (nt.unloadEventEnd – nt.unloadEventStart) + 'ms';

    navigation += ' Redirect: ' + (nt.redirectEnd – nt.redirectStart) + 'ms';

    navigation += ' App Cache: ' + (nt. domainLookupStart – nt.fetchStart) + 'ms';

    navigation += ' DNS: ' + (nt.domainLookupEnd – nt.domainLookupStart) + 'ms';

    navigation += ' TCP: ' + (nt.connectEnd – nt.connectStart) + 'ms';

    navigation += ' Request: ' + (nt.responseStart – nt.requestStart) + 'ms';

    navigation += ' Response: ' + (nt.responseEnd – nt.responseStart) + 'ms';

    navigation += ' Processing: ' + (nt.domComplete – nt.domLoading) + 'ms';

    navigation += ' Load Event: ' + (nt.loadEventEnd – nt.loadEventStart) + 'ms';

    sendAnalytics(navigation);

    }

    </script>

    </body>

    </html>