Re: [WebTiming] Exporting flattened DOMTiming data

Using the onload event is a good idea, but has drawbacks:
1. Some interesting network loads don't generate a load event (XHR,
CSS background image, CSS @import, redirect, object subresource, etc)
2. We'd like lazy loaded analytics scripts to have access to timings
even if they are loaded after other resources have loaded

Dimitri Glazkov had an excellent solution: a collector object. We
expose a createResourceTimingCollector() method which creates a
ResourceTimingCollector that has add/removeEventListener() methods. An
RTC created prior to the completion of the window's onload event is
guaranteed to collect ResourceTimings for all subresources on the page
(even if they completed prior to its creation). EventListeners can be
added later. ResourceTimingEvents contain an array of all
ResourceTimings since the last event.

The usage is clean:
// At any time prior to completion of onload event.
var rtc = createResourceTimingCollector();
// At any subsequent time (irrespective of onload).
rtc.addEventListener(function (event) {
  for (int i = 0; i < event.timings.length; i++) {

The browser has optimizations:
1. ResourceTimings can be deleted after onload if no RTCs exist
2. ResourceTimings can be deleted after they have been dispatched by all RTCs
3. Multiple ResourceTimings can be batched

Here's how the interface would change:

// Existing, unchanged
interface DOMTiming {
  readonly attribute unsigned longlong fetchStart;
  readonly attribute unsigned longlong domainLookupStart;
  readonly attribute unsigned longlong domainLookupEnd;
  readonly attribute unsigned longlong connectStart;
  readonly attribute unsigned longlong connectEnd;
  readonly attribute unsigned longlong requestStart;
  readonly attribute unsigned longlong requestEnd;
  readonly attribute unsigned longlong responseStart;
  readonly attribute unsigned longlong responseEnd;
  readonly attribute unsigned longlong load;
  readonly attribute unsigned longlong parseStart;
  readonly attribute unsigned longlong parseEnd;

// Existing, remove extendedTiming
interface NavigationTiming {
  // REMOVE: readonly attribute boolean extendedTiming;

  const unsigned short NAVIGATION_OTHER = 0;
  const unsigned short NAVIGATION_LINK = 1;
  const unsigned short NAVIGATION_REDIRECT_SERVER = 2;
  const unsigned short NAVIGATION_REDIRECT_CLIENT = 3;
  const unsigned short NAVIGATION_FORWARD_BACK = 4;
  const unsigned short NAVIGATION_USER_BROWSER = 5;
  const unsigned short NAVIGATION_NEW_WINDOW = 6;
  const unsigned short NAVIGATION_RELOAD = 7;
  readonly attribute unsigned short navigationType;

  readonly attribute unsigned longlong navigationStart;
  readonly attribute unsigned longlong lastUnload;
  readonly attribute DOMTiming rootTimes;

// New
interface ResourceTiming {
  const unsigned short TYPE_OTHER = 0;
  const unsigned short TYPE_SCRIPT = 1;
  const unsigned short TYPE_IMAGE = 2;
  const unsigned short TYPE_CSSIMAGE = 3;
  const unsigned short TYPE_FAVICON = 4;
  const unsigned short TYPE_STYLESHEET = 5;
  const unsigned short TYPE_OBJECT = 6;
  const unsigned short TYPE_SUBDOCUMENT = 7;
  const unsigned short TYPE_REDIRECT = 8;
  const unsigned short TYPE_XMLHTTPREQUEST = 9;
  const unsigned short TYPE_OBJECT_SUBREQUEST = 10;
  readonly attribute unsigned short type;

  readonly attribute DOMString url;
  readonly attribute DOMTiming rootTimes;

// New
interface ResourceTimingCollector {
  void addEventListener(in EventListener listener)
  void removeEventListener(in EventListener listener)

// New
interface ResourceTimingEvent : Event {
  readonly attribute array[ResourceTiming] timings;

// [Supplemental]
// interface HTMLElement {
//  readonly attribute DOMTiming timing;
// };

// Existing, add createResourceTimingCollector()
interface Window {  // Perhaps Document instead of Window?
  readonly attribute array[NavigationTiming] timings;
  ResourceTimingCollector createResourceTimingCollector()

Received on Thursday, 29 April 2010 07:04:54 UTC