1. Introduction
This section is non-normative.
Web
developers
need
the
ability
to
assess
and
understand
the
performance
characteristics
of
their
applications.
While
JavaScript
[ECMA-262]
provides
a
mechanism
to
measure
application
latency
(retrieving
the
current
timestamp
from
the
Date.now()
method),
the
precision
of
this
timestamp
varies
between
user
agents.
This
document
defines
the
PerformanceMark
and
PerformanceMeasure
interfaces,
and
extensions
to
the
Performance
interface,
which
expose
a
high
precision,
monotonically
increasing
timestamp
so
that
developers
can
better
measure
the
performance
characteristics
of
their
applications.
The following script shows how a developer can use the interfaces defined in this document to obtain timing data related to developer scripts.
async function run() { performance. mark( "startTask1" ); await doTask1(); // Some developer code performance. mark( "endTask1" ); performance. mark( "startTask2" ); await doTask2(); // Some developer code performance. mark( "endTask2" ); // Log them out const entries= performance. getEntriesByType( "mark" ); for ( const entryof entries) { console. table( entry. toJSON()); } } run();
[PERFORMANCE-TIMELINE-2]
defines
two
mechanisms
that
can
be
used
to
retrieve
recorded
metrics:
getEntries()
and
getEntriesByType()
methods,
and
the
PerformanceObserver
interface.
The
former
is
best
suited
for
cases
where
you
want
to
retrieve
a
particular
metric
by
name
at
a
single
point
in
time,
and
the
latter
is
optimized
for
cases
where
you
may
want
to
receive
notifications
of
new
metrics
as
they
become
available.
As another example, suppose that there is an element which, when clicked, fetches some new content and indicates that it has been fetched. We’d like to report the time from when the user clicked to when the fetch was complete. We can’t mark the time the click handler executes since that will miss latency to process the event, so instead we use the event hardware timestamp. We also want to know the name of the component to have more detailed analytics.
element. addEventListener( "click" , e=> { const component= getComponent( element); fetch( component. url). then(() => { element. textContent= "Updated" ; const updateMark= performance. mark( "update_component" , { detail: { component: component. name}, }); performance. measure( "click_to_update_component" , { detail: { component: component. name}, start: e. timeStamp, end: updateMark. startTime, }); }); });
2. User Timing
2.1.
Extensions
to
the
Performance
interface
The
Performance
interface
and
DOMHighResTimeStamp
are
defined
in
[HR-TIME-2]
.
The
PerformanceEntry
interface
is
defined
in
[PERFORMANCE-TIMELINE-2]
.
dictionary {PerformanceMarkOptions any ;detail DOMHighResTimeStamp ; };startTime dictionary {PerformanceMeasureOptions any ; (detail DOMString or DOMHighResTimeStamp );start DOMHighResTimeStamp ; (duration DOMString or DOMHighResTimeStamp ); };end partial interface Performance {PerformanceMark (mark DOMString ,markName optional PerformanceMarkOptions = {});markOptions undefined (clearMarks optional DOMString );markName PerformanceMeasure (measure DOMString ,measureName optional (DOMString or PerformanceMeasureOptions )= {},startOrMeasureOptions optional DOMString );endMark undefined (clearMeasures optional DOMString ); };measureName
2.1.1. mark() method
Stores a timestamp with the associated name (a "mark"). It MUST run these steps:
- Run the PerformanceMark constructor and let entry be the newly created object.
- Queue a PerformanceEntry entry .
- Add entry to the performance entry buffer .
- Return entry .
2.1.1.1. PerformanceMarkOptions dictionary
- detail
- Metadata to be included in the mark.
- startTime
- Timestamp to be used as the mark time.
2.1.2. clearMarks() method
Removes the stored timestamp with the associated name. It MUST run these steps:
- If markName is omitted, remove all PerformanceMark objects from the performance entry buffer .
- Otherwise, remove all PerformanceMark objects listed in the performance entry buffer whose name is markName .
- Return undefined .
2.1.3. measure() method
Stores
the
DOMHighResTimeStamp
duration
between
two
marks
along
with
the
associated
name
(a
"measure").
It
MUST
run
these
steps:
- If startOrMeasureOptions is a PerformanceMeasureOptions object and at least one of start , end , duration , and detail exist , run the following checks:
-
Compute
end
time
as
follows:
- If endMark is given, let end time be the value returned by running the convert a mark to a timestamp algorithm passing in endMark .
- Otherwise, if startOrMeasureOptions is a PerformanceMeasureOptions object, and if its end member exists , let end time be the value returned by running the convert a mark to a timestamp algorithm passing in startOrMeasureOptions ’s end .
-
Otherwise,
if
startOrMeasureOptions
is
a
PerformanceMeasureOptions
object,
and
if
its
start
and
duration
members
both
exist
:
- Let start be the value returned by running the convert a mark to a timestamp algorithm passing in start .
- Let duration be the value returned by running the convert a mark to a timestamp algorithm passing in duration .
- Let end time be start plus duration .
-
Otherwise,
let
end
time
be
the
value
that
would
be
returned
by
the
Performanceobject’snow()method.
-
Compute
start
time
as
follows:
- If startOrMeasureOptions is a PerformanceMeasureOptions object, and if its start member exists , let start time be the value returned by running the convert a mark to a timestamp algorithm passing in startOrMeasureOptions ’s start .
-
Otherwise,
if
startOrMeasureOptions
is
a
PerformanceMeasureOptions
object,
and
if
its
duration
and
end
members
both
exist
:
- Let duration be the value returned by running the convert a mark to a timestamp algorithm passing in duration .
- Let end be the value returned by running the convert a mark to a timestamp algorithm passing in end .
- Let start time be end minus duration .
-
Otherwise,
if
startOrMeasureOptions
is
a
DOMString, let start time be the value returned by running the convert a mark to a timestamp algorithm passing in startOrMeasureOptions . -
Otherwise,
let
start
time
be
0.
- Create a new PerformanceMeasure object ( entry ) with this ’s relevant realm .
-
Set
entry
’s
nameattribute to measureName . -
Set
entry
’s
entryTypeattribute toDOMString "measure". -
Set
entry
’s
startTimeattribute to start time . -
Set
entry
’s
durationattribute to the duration from start time to end time . The resulting duration value MAY be negative. -
Set
entry
’s
detailattribute as follows:-
If
startOrMeasureOptions
is
a
PerformanceMeasureOptions
object
and
startOrMeasureOptions
’s
detail
member
exists
:
- Let record be the result of calling the StructuredSerialize algorithm on startOrMeasureOptions ’s detail .
- Set entry ’s detail to the result of calling the StructuredDeserialize algorithm on record and the current realm .
-
Otherwise,
set
it
to
null.
-
If
startOrMeasureOptions
is
a
PerformanceMeasureOptions
object
and
startOrMeasureOptions
’s
detail
member
exists
:
- Queue a PerformanceEntry entry .
- Add entry to the performance entry buffer .
- Return entry .
2.1.3.1. PerformanceMeasureOptions dictionary
- detail
- Metadata to be included in the measure.
- start
- Timestamp to be used as the start time or string to be used as start mark.
- duration
- Duration between the start and end times.
- end
- Timestamp to be used as the end time or string to be used as end mark.
2.1.4. clearMeasures() method
Removes stored timestamp with the associated name. It MUST run these steps:
- If measureName is omitted, remove all PerformanceMeasure objects in the performance entry buffer .
-
Otherwise
remove
all
PerformanceMeasure
objects
listed
in
the
performance
entry
buffer
whose
nameis measureName . - Return undefined .
2.2. The PerformanceMark Interface
The
PerformanceMark
interface
also
exposes
marks
created
via
the
Performance
interface’s
mark()
method
to
the
Performance
Timeline
.
[Exposed =(Window ,Worker )]interface :PerformanceMark PerformanceEntry {(constructor DOMString ,markName optional PerformanceMarkOptions = {});markOptions ;readonly attribute any detail ; };
The
PerformanceMark
interface
extends
the
following
attributes
of
the
PerformanceEntry
interface:
The
name
attribute
must
return
the
mark’s
name.
The
entryType
attribute
must
return
the
DOMString
"mark"
.
The
startTime
attribute
must
return
a
DOMHighResTimeStamp
with
the
mark’s
time
value.
The
duration
attribute
must
return
a
DOMHighResTimeStamp
of
value
0
.
The PerformanceMark interface contains the following additional attribute:
The
detail
attribute
must
return
the
value
it
is
set
to
(it’s
copied
from
the
PerformanceMarkOptions
dictionary).
2.2.1. The PerformanceMark Constructor
The PerformanceMark constructor must run the following steps:
-
If
the
current
global
object
is
a
Windowobject and markName uses the same name as a read only attribute in thePerformanceTiminginterface, throw aSyntaxError. - Create a new PerformanceMark object ( entry ) with the current global object ’s realm .
-
Set
entry
’s
nameattribute to markName . -
Set
entry
’s
entryTypeattribute toDOMString "mark". -
Set
entry
’s
startTimeattribute as follows: -
Set
entry
’s
durationattribute to0. - If markOptions ’s detail is null, set entry ’s detail to null.
-
Otherwise:
- Let record be the result of calling the StructuredSerialize algorithm on markOptions ’s detail .
- Set entry ’s detail to the result of calling the StructuredDeserialize algorithm on record and the current realm .
2.3. The PerformanceMeasure Interface
The
PerformanceMeasure
interface
also
exposes
measures
created
via
the
Performance
interface’s
measure()
method
to
the
Performance
Timeline
.
[Exposed =(Window ,Worker )]interface :PerformanceMeasure PerformanceEntry {;readonly attribute any detail ; };
The
PerformanceMeasure
interface
extends
the
following
attributes
of
the
PerformanceEntry
interface:
The
name
attribute
must
return
the
measure’s
name.
The
entryType
attribute
must
return
the
DOMString
"measure"
.
The
startTime
attribute
must
return
a
DOMHighResTimeStamp
with
the
measure’s
start
mark.
The
duration
attribute
must
return
a
DOMHighResTimeStamp
with
the
duration
of
the
measure.
The PerformanceMeasure interface contains the following additional attribute:
The
detail
attribute
must
return
the
value
it
is
set
to
(it’s
copied
from
the
PerformanceMeasureOptions
dictionary).
3. Processing
A
user
agent
implementing
the
User
Timing
API
would
need
to
include
"mark"
and
"measure"
in
supportedEntryTypes
.
This
allows
developers
to
detect
support
for
User
Timing.
3.1. Convert a mark to a timestamp
To
convert
a
mark
to
a
timestamp
,
given
a
mark
that
is
a
DOMString
or
DOMHighResTimeStamp
run
these
steps:
-
If
mark
is
a
DOMStringand it has the same name as a read only attribute in thePerformanceTiminginterface, let end time be the value returned by running the convert a name to a timestamp algorithm with name set to the value of mark . -
Otherwise,
if
mark
is
a
DOMString, let end time be the value of thestartTimeattribute from the most recent occurrence of a PerformanceMark object in the performance entry buffer whosenameis mark . If no matching entry is found, throw aSyntaxError. -
Otherwise,
if
mark
is
a
DOMHighResTimeStamp:-
If
mark
is
negative,
throw
a
TypeError. - Otherwise, let end time be mark .
-
If
mark
is
negative,
throw
a
3.2. Convert a name to a timestamp
To
convert
a
name
to
a
timestamp
given
a
name
that
is
a
read
only
attribute
in
the
PerformanceTiming
interface,
run
these
steps:
-
If
the
global
object
is
not
a
Windowobject, throw aTypeError. -
If
name
is
navigationStart, return0. -
Let
startTime
be
the
value
of
navigationStartin thePerformanceTiminginterface. -
Let
endTime
be
the
value
of
name
in
the
PerformanceTiminginterface. -
If
endTime
is
0, throw anInvalidAccessError. - Return result of subtracting startTime from endTime .
The PerformanceTiming interface was defined in [NAVIGATION-TIMING] and is now considered obsolete. The use of names from the PerformanceTiming interface is supported to remain backwards compatible, but there are no plans to extend this functionality to names in the PerformanceNavigationTiming interface defined in [NAVIGATION-TIMING-2] (or other interfaces) in the future.
4. Recommended mark names
Developers are encouraged to use the following recommended mark names to mark common timings. The user agent does not validate that the usage of these names is appropriate or consistent with its description.
Adding such recommended mark names can help performance tools tailor guidance to a site. These mark names can also help real user monitoring providers and user agents collect web developer signals regarding their application’s performance at scale, and surface this information to developers without requiring any site-specific work.
- " mark_fully_loaded "
-
The
time
when
the
page
is
considered
fully
loaded
as
marked
by
the
developer
in
their
application.
In this example, the page asynchonously initializes a chat widget, a searchbox, and a newsfeed upon loading. When finished, the " mark_fully_loaded " mark name enables lab tools and analytics providers to automatically show the timing.
window
. addEventListener( "load" , ( event) => { Promise. all([ loadChatWidget(), initializeSearchAutocomplete(), initializeNewsfeed()]). then(() => { performance. mark( 'mark_fully_loaded' ); }); }); - " mark_fully_visible "
- The time when the page is considered fully visible to an end-user as marked by the developer in their application.
- " mark_interactive "
- The time when the page is considered interactive to an end-user as marked by the developer in their application.
- " mark_feature_usage "
-
Mark
the
usage
of
a
feature
which
may
impact
performance
so
that
tooling
and
analytics
can
take
it
into
account.
The
detail
metadata
can
contain
any
useful
information
about
the
feature,
including:
- feature
- The name of the feature used.
- framework
- If applicable, the underlying framework the feature is intended for, such as a JavaScript framework, content management system, or e-commerce platform.
In this example, the ImageOptimizationComponent for FancyJavaScriptFramework is used to size images for optimal performance. The code notes this feature’s usage so that lab tools and analytics can measure whether it helped improve performance.
performance
. mark( 'mark_feature_usage' , { 'detail' : { 'feature' : 'ImageOptimizationComponent' , 'framework' : 'FancyJavaScriptFramework' } })
5. Privacy and Security
This section is non-normative.
The interfaces defined in this specification expose potentially sensitive timing information on specific JavaScript activity of a page. Please refer to [HR-TIME-2] for privacy and security considerations of exposing high-resolution timing information.
Because the web platform has been designed with the invariant that any script included on a page has the same access as any other script included on the same page, regardless of the origin of either scripts, the interfaces defined by this specification do not place any restrictions on recording or retrieval of recorded timing information - i.e. a user timing mark or measure recorded by any script included on the page can be read by any other script running on the same page, regardless of origin.
Acknowledgments
Thanks to James Simonsen, Jason Weber, Nic Jansma, Philippe Le Hegaret, Karen Anderson, Steve Souders, Sigbjorn Vik, Todd Reifsteck, and Tony Gentilcore for their contributions to this work.