Copyright © 2019 W3C® (MIT, ERCIM, Keio, Beihang). W3C liability, trademark and permissive document license rules apply.
This specification extends the High Resolution Time specification [HR-TIME-2] by providing methods to store and retrieve high resolution performance metric data.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.
Performance Timeline Level 2 replaces the first version of [PERFORMANCE-TIMELINE] and includes:
PerformanceEntry in Web Workers [WORKERS];
      This document is ready for wide review.
This document was published by the Web Performance Working Group as a Working Draft. This document is intended to become a W3C Recommendation.
GitHub Issues are preferred for discussion of this specification.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This document is governed by the 1 March 2019 W3C Process Document.
This section is non-normative.
Accurately measuring performance characteristics of web applications is an important aspect of making web applications faster. This specification defines the necessary Performance Timeline primitives that enable web developers to access, instrument, and retrieve various performance metrics from the full lifecycle of a web application.
[NAVIGATION-TIMING-2], [RESOURCE-TIMING-2], and [USER-TIMING-2] are examples of specifications that define timing information related to the navigation of the document, resources on the page, and developer scripts, respectively. Together these and other performance interfaces define performance metrics that describe the Performance Timeline of a web application. For example, the following script shows how a developer can access the Performance Timeline to obtain performance metrics related to the navigation of the document, resources on the page, and developer scripts:
<!doctype html>
<html>
<head></head>
<body onload="init()">
  <img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
  <script>
    function init() {
      // see [[USER-TIMING-2]]
      performance.mark("startWork");
      doWork(); // Some developer code
      performance.mark("endWork");
      measurePerf();
    }
    function measurePerf() {
      performance
        .getEntries()
        .map(entry => JSON.stringify(entry, null, 2))
        .forEach(json => console.log(json));
    }
  </script>
  </body>
</html>Alternatively, the developer can observe the Performance Timeline
    and be notified of new performance metrics, via the PerformanceObserver
    interface:
<!doctype html>
<html>
<head></head>
<body>
<img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
<script>
// Know when the entry types we would like to use are not supported.
function detectSupport(entryTypes) {
  for (const entryType of entryTypes) {
    if (!PerformanceObserver.supportedEntryTypes.includes(entryType)) {
      // Indicate to client-side analytics that |entryType| is not supported.
    }
  }
}
detectSupport(["resource", "mark", "measure"]);
const userTimingObserver = new PerformanceObserver(list => {
  list
    .getEntries()
    // Get the values we are interested in
    .map(({ name, entryType, startTime, duration }) => {
      const obj = {
        "Duration": duration,
        "Entry Type": entryType,
        "Name": name,
        "Start Time": startTime,
      };
      return JSON.stringify(obj, null, 2);
    })
    // Display them to the console.
    .forEach(console.log);
  // Disconnect after processing the events.
  userTimingObserver.disconnect();
});
// Subscribe to new events for User-Timing.
userTimingObserver.observe({entryTypes: ["mark", "measure"]});
const resourceObserver = new PerformanceObserver(list => {
  list
    .getEntries()
    // Get the values we are interested in
    .map(({ name, startTime, fetchStart, responseStart, responseEnd }) => {
      const obj = {
        "Name": name,
        "Start Time": startTime,
        "Fetch Start": fetchStart,
        "Response Start": responseStart,
        "Response End": responseEnd,
      };
      return JSON.stringify(obj, null, 2);
    })
    // Display them to the console.
    .forEach(console.log);
  // Disconnect after processing the events.
  resourceObserver.disconnect();
});
// Subscribe to new events for Resource Timing.
resourceObserver.observe({type: "resource"});
</script>
</body>
</html>The PerformanceObserver interface was added in Performance
Timeline Level 2 and is designed to address limitations of the buffer-based
approach shown in the first example. By using the PerformanceObserver
interface, the application can:
The developer is encouraged to use PerformanceObserver where
possible. Further, new performance API's and metrics may only be available
through the PerformanceObserver interface.
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words MUST, MUST NOT, and SHOULD in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)
Each ECMAScript global environment has:
PerformanceEntry objects that is initially empty
The relevant performance entry buffer is the performance entry buffer associated with the relevant global object of the context object.
Performance interfaceThis extends the Performance interface [HR-TIME-2] and hosts performance related attributes and methods used to retrieve the performance metric data from the Performance Timeline.
partial interfacePerformance{PerformanceEntryListgetEntries();PerformanceEntryListgetEntriesByType(DOMString type);PerformanceEntryListgetEntriesByName(DOMString name, optional DOMString type); }; typedef sequence<PerformanceEntry>PerformanceEntryList;
The PerformanceEntryList represents a sequence of
      PerformanceEntry, providing developers with all the convenience
methods found on JavaScript arrays.
getEntries() methodReturns a PerformanceEntryList object returned by § 4.2 Filter buffer by name and type algorithm with buffer
        set to relevant performance entry buffer, and name
        and type set to null.
getEntriesByType() methodReturns a PerformanceEntryList object returned by § 4.2 Filter buffer by name and type algorithm with buffer
        set to relevant performance entry buffer, name set to
        null, and type set to type.
getEntriesByName() methodReturns a PerformanceEntryList object returned by § 4.2 Filter buffer by name and type algorithm with buffer
        set to relevant performance entry buffer, name set to
name, and type set to null if optional
entryType is omitted, and type set to type
otherwise.
PerformanceEntry interfaceThe PerformanceEntry interface hosts the performance data of
various metrics.
[Exposed=(Window,Worker)]
interface PerformanceEntry {
  readonly    attribute DOMString           name;
  readonly    attribute DOMString           entryType;
  readonly    attribute DOMHighResTimeStamp startTime;
  readonly    attribute DOMHighResTimeStamp duration;
  [Default] object toJSON();
};namePerformanceEntry object. This identifier does not have to be
unique.
entryTypePerformanceEntry object.
          Example entryType values defined by other
specifications include: "mark" and
          "measure" [USER-TIMING-2], "navigation"
          [NAVIGATION-TIMING-2], "resource"
          [RESOURCE-TIMING-2], 
           and "longtask".
startTimestartTime of
0.durationPerformanceEntry.
Typically, this would be the time difference between the last
recorded timestamp and the first recorded timestamp of this
PerformanceEntry. If the duration concept doesn't apply, a
performance metric may choose to return a duration of
0.
When toJSON is called, run [WebIDL]'s default toJSON operation.
PerformanceObserver interfaceThe PerformanceObserver interface can be used to observe the
      Performance Timeline to be notified of new performance metrics as
they are recorded.
Each PerformanceObserver has these associated concepts:
PerformanceObserverCallback set on creation.PerformanceEntryList object called the observer
        buffer that is initially empty.DOMString
observer type which is initially
        "undefined".The PerformanceObserver(callback) constructor must create a new
PerformanceObserver object with PerformanceObserverCallback
      set to callback and then return it.
A registered performance observer is a struct consisting of an
      observer member (a PerformanceObserver object) and an
      options list member (a list of PerformanceObserverInit
      dictionaries).
callbackPerformanceObserverCallback= void (PerformanceObserverEntryListentries,PerformanceObserverobserver); [Constructor(PerformanceObserverCallbackcallback), Exposed=(Window,Worker)] interfacePerformanceObserver{ voidobserve(PerformanceObserverInitoptions); voiddisconnect();PerformanceEntryListtakeRecords(); [SameObject] static readonly attribute FrozenArray<DOMString>supportedEntryTypes; };
To keep the performance overhead to minimum the application ought to only subscribe to event types that it is interested in, and disconnect the observer once it no longer needs to observe the performance data. Filtering by name is not supported, as it would implicitly require a subscription for all event types — this is possible, but discouraged, as it will generate a significant volume of events.
observe() methodThe observe() method instructs the user agent to
        register the observer and must run these steps:
entryTypes and type members
are both omitted, then throw a
          SyntaxError.entryTypes is present and any other
member is also present, then
throw a
          SyntaxError."undefined":
                entryTypes member is
present, then set observer's observer type
                  to "multiple".type member is present,
then set observer's observer type to
                  "single"."single" and options's
              entryTypes member is present, then
              throw an
              
              InvalidModificationError.
              "multiple" and options's type
              member is present, then throw
              an 
              InvalidModificationError.
"multiple", run the following steps:
          entryTypes sequence.
            "single".type is not contained in the
            relevantGlobal's frozen array of supported entry types,
abort these steps. The user agent SHOULD notify developers when this
happens, for instance via a console warning.PerformanceObserverInit item currentOptions
                whose type is equal to options's type,
replace currentOptions with options in
                obs's options list.A PerformanceObserver object needs to always call
        observe() with options's
        entryTypes set OR always
call observe() with options's
        type set. If one
        PerformanceObserver calls observe() with entryTypes and also calls observe with
        type, then an exception is
thrown. This is meant to avoid confusion with how calls would stack.
When using entryTypes, no
other parameters in PerformanceObserverInit can be used. In
addition, multiple observe() calls will override for backwards
compatibility and because a single call should suffice in this case. On
the other hand, when using
type, calls will stack
because a single call can only specify one type. Calling
observe() with a repeated type will also override.
PerformanceObserverInit dictionarydictionary PerformanceObserverInit {
  sequence<DOMString> entryTypes;
  DOMString type;
};entryTypestypePerformanceObserverEntryList interface[Exposed=(Window,Worker)]
interface PerformanceObserverEntryList {
  PerformanceEntryList getEntries();
  PerformanceEntryList getEntriesByType (DOMString type);
  PerformanceEntryList getEntriesByName (DOMString name, optional DOMString type);
};getEntries() methodReturns a PerformanceEntryList object returned by
            § 4.2 Filter buffer by name and type algorithm with
            buffer set to observer buffer, and
            name and type set to null.
getEntriesByType() methodReturns a PerformanceEntryList object returned by
            § 4.2 Filter buffer by name and type algorithm with
            buffer set to observer buffer, name
            set to null, and type set to type.
getEntriesByName() methodReturns a PerformanceEntryList object returned by
            § 4.2 Filter buffer by name and type algorithm with
            buffer set to observer buffer, name
            set to name, and type set to null if
optional entryType is omitted, and type set to type
otherwise.
takeRecords() methodThe takeRecords() method must return a copy of the
        context object's
        observer buffer, and also empty context object's observer
        buffer.
disconnect() methodThe disconnect() method must remove the context object from the list of
        registered performance observer objects of relevant global
        object, and also empty context object's observer
        buffer.
supportedEntryTypes attributeEach global object has an associated frozen array of supported entry types, which is initialized to the FrozenArray created from the sequence of strings among the registry that are supported for the global object, in alphabetical order.
When supportedEntryTypes's attribute getter is called, run the following steps:
This attribute allows web developers to easily know which entry types are supported by the user agent.
PerformanceEntryTo queue a PerformanceEntry (new entry) with an optional add to performance entry buffer flag, which is unset by default, run these steps:
PerformanceObserver objects.
entryType value.PerformanceObserverInit item whose
            entryTypes member
includes entryType or whose
            type member equals to
            entryType, append regObs's observer
            to interested observers.
PerformanceObserver object po in
            notify list, run these steps:
              The performance timeline task queue is a low priority queue that, if possible, should be processed by the user agent during idle periods to minimize impact of performance monitoring code.
Given a buffer and optional name and
      type string values this algorithm returns a
      PerformanceEntryList object that contains a list of
      PerformanceEntry objects sorted in chronological order with
respect to startTime; objects with the same startTime have
unspecified ordering.
PerformanceEntryList.
PerformanceEntry object (entryObject) in
the buffer, in chronological order with respect to
        startTime:
          null and
            entryObject's name attribute does not match
            name in a case-sensitive
            manner, go to next entryObject.
null and
            entryObject's type attribute does not match
            type in a case-sensitive
            manner, go to next entryObject.
This specification extends the Performance interface defined by [HR-TIME-2] and provides methods to queue and retrieve entries from the performance timeline. Please refer to [HR-TIME-2] for privacy and security considerations of exposing high-resoluting timing information.
partial interfacePerformance{PerformanceEntryListgetEntries();PerformanceEntryListgetEntriesByType(DOMString type);PerformanceEntryListgetEntriesByName(DOMString name, optional DOMString type); }; typedef sequence<PerformanceEntry>PerformanceEntryList; [Exposed=(Window,Worker)] interfacePerformanceEntry{ readonly attribute DOMStringname; readonly attribute DOMStringentryType; readonly attribute DOMHighResTimeStampstartTime; readonly attribute DOMHighResTimeStampduration; [Default] objecttoJSON(); }; callbackPerformanceObserverCallback= void (PerformanceObserverEntryListentries,PerformanceObserverobserver); [Constructor(PerformanceObserverCallbackcallback), Exposed=(Window,Worker)] interfacePerformanceObserver{ voidobserve(PerformanceObserverInitoptions); voiddisconnect();PerformanceEntryListtakeRecords(); [SameObject] static readonly attribute FrozenArray<DOMString>supportedEntryTypes; }; dictionaryPerformanceObserverInit{ sequence<DOMString>entryTypes; DOMStringtype; }; [Exposed=(Window,Worker)] interfacePerformanceObserverEntryList{PerformanceEntryListgetEntries();PerformanceEntryListgetEntriesByType(DOMString type);PerformanceEntryListgetEntriesByName(DOMString name, optional DOMString type); };
Thanks to Arvind Jain, Boris Zbarsky, Jatinder Mann, Nat Duca, Philippe Le Hegaret, Ryosuke Niwa, Shubhie Panicker, Todd Reifsteck, Yoav Weiss, and Zhiheng Wang, for their contributions to this work.